Merge remote-tracking branch 'origin/development' into config_from_dream3D

This commit is contained in:
Martin Diehl 2021-03-12 08:09:25 +01:00
commit 3b27c64709
144 changed files with 7801 additions and 7780 deletions

View File

@ -95,7 +95,7 @@ checkout:
- release
###################################################################################################
Pytest_python:
pytest_python:
stage: python
script:
- cd $DAMASKROOT/python
@ -252,7 +252,7 @@ setup_mesh:
- release
###################################################################################################
Pytest_grid:
pytest_fortran:
stage: grid
script:
- module load $IntelCompiler $MPI_Intel $PETSc_Intel
@ -287,14 +287,6 @@ J2_plasticBehavior:
- master
- release
Marc_elementLib:
stage: marc
script:
- module load $IntelMarc $HDF5Marc $MSC
- Marc_elementLib/test.py
except:
- master
- release
###################################################################################################
SpectralRuntime:

4
.gitmodules vendored
View File

@ -1,5 +1,5 @@
[submodule "PRIVATE"]
path = PRIVATE
path = PRIVATE
url = ../PRIVATE.git
branch = master
shallow = true
shallow = true

View File

@ -84,7 +84,7 @@ for executable in python python3; do
done
secondLevel "Details on $DEFAULT_PYTHON:"
echo $(ls -la $(which $DEFAULT_PYTHON))
for module in numpy scipy pandas;do
for module in numpy scipy pandas matplotlib yaml h5py;do
thirdLevel $module
$DEFAULT_PYTHON -c "import $module; \
print('Version: {}'.format($module.__version__)); \
@ -94,10 +94,6 @@ thirdLevel vtk
$DEFAULT_PYTHON -c "import vtk; \
print('Version: {}'.format(vtk.vtkVersion.GetVTKVersion())); \
print('Location: {}'.format(vtk.__file__))"
thirdLevel h5py
$DEFAULT_PYTHON -c "import h5py; \
print('Version: {}'.format(h5py.version.version)); \
print('Location: {}'.format(h5py.__file__))"
firstLevel "GNU Compiler Collection"
for executable in gcc g++ gfortran ;do

View File

@ -1,4 +1,4 @@
Copyright 2011-20 Max-Planck-Institut für Eisenforschung GmbH
Copyright 2011-21 Max-Planck-Institut für Eisenforschung GmbH
DAMASK is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

@ -1 +1 @@
Subproject commit 45ef93dbfa3e0e6fa830914b3632e188c308a099
Subproject commit 13dfa0ee9d702782f0b7999f3f7fb2384f58d768

View File

@ -1 +1 @@
v3.0.0-alpha2-173-g584c7cc3a
v3.0.0-alpha2-602-ge2d4ab427

6
env/CONFIG vendored
View File

@ -1,5 +1,5 @@
# "set"-syntax needed only for tcsh (but works with bash and zsh)
set DAMASK_NUM_THREADS = 4
set OMP_NUM_THREADS = 4
set MSC_ROOT = /opt/msc
set MSC_VERSION = 2020
set MSC_ROOT = /opt/msc
set MSC_VERSION = 2020

54
env/DAMASK.csh vendored
View File

@ -1,54 +0,0 @@
# sets up an environment for DAMASK on tcsh
# usage: source DAMASK_env.csh
set CALLED=($_)
set ENV_ROOT=`dirname $CALLED[2]`
set DAMASK_ROOT=`python3 -c "import os,sys; print(os.path.realpath(os.path.expanduser(sys.argv[1])))" $ENV_ROOT"/../"`
source $ENV_ROOT/CONFIG
set path = ($DAMASK_ROOT/bin $path)
set SOLVER=`which DAMASK_grid`
if ( "x$DAMASK_NUM_THREADS" == "x" ) then
set DAMASK_NUM_THREADS=1
endif
# currently, there is no information that unlimited stack size causes problems
# still, http://software.intel.com/en-us/forums/topic/501500 suggest to fix it
# more info https://jblevins.org/log/segfault
# https://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap
# http://superuser.com/questions/220059/what-parameters-has-ulimit
limit stacksize unlimited # maximum stack size (kB)
# disable output in case of scp
if ( $?prompt ) then
echo ''
echo Düsseldorf Advanced Materials Simulation Kit --- DAMASK
echo Max-Planck-Institut für Eisenforschung GmbH, Düsseldorf
echo https://damask.mpie.de
echo
echo Using environment with ...
echo "DAMASK $DAMASK_ROOT"
echo "Grid Solver $SOLVER"
if ( $?PETSC_DIR) then
echo "PETSc location $PETSC_DIR"
endif
if ( $?MSC_ROOT) then
echo "MSC.Marc/Mentat $MSC_ROOT"
endif
echo
echo "Multithreading DAMASK_NUM_THREADS=$DAMASK_NUM_THREADS"
echo `limit datasize`
echo `limit stacksize`
echo
endif
setenv DAMASK_NUM_THREADS $DAMASK_NUM_THREADS
if ( ! $?PYTHONPATH ) then
setenv PYTHONPATH $DAMASK_ROOT/python
else
setenv PYTHONPATH $DAMASK_ROOT/python:$PYTHONPATH
endif
setenv MSC_ROOT
setenv MSC_VERSION

10
env/DAMASK.sh vendored
View File

@ -38,7 +38,7 @@ PATH=${DAMASK_ROOT}/bin:$PATH
SOLVER=$(type -p DAMASK_grid || true 2>/dev/null)
[ "x$SOLVER" == "x" ] && SOLVER=$(blink 'Not found!')
[ "x$DAMASK_NUM_THREADS" == "x" ] && DAMASK_NUM_THREADS=1
[ "x$OMP_NUM_THREADS" == "x" ] && OMP_NUM_THREADS=1
# currently, there is no information that unlimited stack size causes problems
# still, http://software.intel.com/en-us/forums/topic/501500 suggest to fix it
@ -66,7 +66,7 @@ if [ ! -z "$PS1" ]; then
echo -n "MSC.Marc/Mentat "
[ -d $MSC_ROOT ] && echo $MSC_ROOT || blink $MSC_ROOT
echo
echo "Multithreading DAMASK_NUM_THREADS=$DAMASK_NUM_THREADS"
echo "Multithreading OMP_NUM_THREADS=$OMP_NUM_THREADS"
echo -n "heap size "
[[ "$(ulimit -d)" == "unlimited" ]] \
&& echo "unlimited" \
@ -86,11 +86,13 @@ if [ ! -z "$PS1" ]; then
echo
fi
export DAMASK_NUM_THREADS
export OMP_NUM_THREADS
export MSC_ROOT
export MSC_VERSION
export DAMASK_ROOT
export PYTHONPATH=$DAMASK_ROOT/python:$PYTHONPATH
for var in BASE STAT SOLVER BRANCH; do
unset "${var}"
done
unset "ENV_ROOT"
unset "DAMASK_ROOT"

10
env/DAMASK.zsh vendored
View File

@ -30,7 +30,7 @@ PATH=${DAMASK_ROOT}/bin:$PATH
SOLVER=$(which DAMASK_grid || true 2>/dev/null)
[[ "x$SOLVER" == "x" ]] && SOLVER=$(blink 'Not found!')
[[ "x$DAMASK_NUM_THREADS" == "x" ]] && DAMASK_NUM_THREADS=1
[[ "x$OMP_NUM_THREADS" == "x" ]] && OMP_NUM_THREADS=1
# currently, there is no information that unlimited stack size causes problems
# still, http://software.intel.com/en-us/forums/topic/501500 suggest to fix it
@ -60,7 +60,7 @@ if [ ! -z "$PS1" ]; then
echo -n "MSC.Marc/Mentat "
[ -d $MSC_ROOT ] && echo $MSC_ROOT || blink $MSC_ROOT
echo
echo "Multithreading DAMASK_NUM_THREADS=$DAMASK_NUM_THREADS"
echo "Multithreading OMP_NUM_THREADS=$OMP_NUM_THREADS"
echo -n "heap size "
[[ "$(ulimit -d)" == "unlimited" ]] \
&& echo "unlimited" \
@ -80,11 +80,13 @@ if [ ! -z "$PS1" ]; then
echo
fi
export DAMASK_NUM_THREADS
export OMP_NUM_THREADS
export MSC_ROOT
export MSC_VERSION
export DAMASK_ROOT
export PYTHONPATH=$DAMASK_ROOT/python:$PYTHONPATH
for var in SOLVER BRANCH; do
unset "${var}"
done
unset "ENV_ROOT"
unset "DAMASK_ROOT"

View File

@ -1,8 +0,0 @@
[SX]
type isostrain
Ngrains 1
{./Homogenization_Damage_NonLocal.config}
{./Homogenization_Thermal_Conduction.config}
{./Homogenization_VacancyFlux_CahnHilliard.config}
{./Homogenization_Porosity_PhaseField.config}
{./Homogenization_HydrogenFlux_CahnHilliard.config}

View File

@ -1,4 +0,0 @@
[DP_Steel]
crystallite 1
(constituent) phase 1 texture 1 fraction 0.82
(constituent) phase 2 texture 2 fraction 0.18

View File

@ -1,64 +0,0 @@
[TWIP_Steel_FeMnC]
elasticity hooke
plasticity dislotwin
(output) rho_mob
(output) rho_dip
(output) gamma_sl
(output) lambda_sl
(output) tau_pass
(output) f_tw
(output) lambda_tw
(output) tau_hat_tw
(output) f_tr
### Material parameters ###
lattice_structure fcc
C11 175.0e9 # From Music et al. Applied Physics Letters 91, 191904 (2007)
C12 115.0e9
C44 135.0e9
grainsize 2.0e-5 # Average grain size [m]
SolidSolutionStrength 1.5e8 # Strength due to elements in solid solution
### Dislocation glide parameters ###
Nslip 12
slipburgers 2.56e-10 # Burgers vector of slip system [m]
rhoedgedip0 1.0 # Initial dislocation density [m/m**3]
rhoedge0 1.0e12 # Initial dislocation density [m/m**3]
v0 1.0e-4 # Initial glide velocity [m/s]
Qedge 3.7e-19 # Activation energy for dislocation glide [J]
p_slip 1.0 # p-exponent in glide velocity
q_slip 1.0 # q-exponent in glide velocity
# hardening of glide
CLambdaSlip 10.0 # Adj. parameter controlling dislocation mean free path
D0 4.0e-5 # Vacancy diffusion prefactor [m**2/s]
Qsd 4.5e-19 # Activation energy for climb [J]
Catomicvolume 1.0 # Adj. parameter controlling the atomic volume [in b^3]
Cedgedipmindistance 1.0 # Adj. parameter controlling the minimum dipole distance [in b]
interactionSlipSlip 0.122 0.122 0.625 0.07 0.137 0.122 # Interaction coefficients (Kubin et al. 2008)
### Shearband parameters ###
shearbandresistance 180e6
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
### Twinning parameters ###
Ntwin 12
twinburgers 1.47e-10 # Burgers vector of twin system [m]
twinsize 5.0e-8 # Twin stack mean thickness [m]
L0_twin 442.0 # Length of twin nuclei in Burgers vectors
maxtwinfraction 1.0 # Maximum admissible twin volume fraction
xc_twin 1.0e-9 # critical distance for formation of twin nucleus
VcrossSlip 1.67e-29 # cross slip volume
r_twin 10.0 # r-exponent in twin formation probability
Cmfptwin 1.0 # Adj. parameter controlling twin mean free path
Cthresholdtwin 1.0 # Adj. parameter controlling twin threshold stress
interactionSlipTwin 0.0 1.0 1.0 # Dislocation-Twin interaction coefficients
interactionTwinTwin 0.0 1.0 # Twin-Twin interaction coefficients
SFE_0K -0.0396 # stacking fault energy at zero K; TWIP steel: -0.0526; Cu: -0.0396
dSFE_dT 0.0002 # temperature dependance of stacking fault energy

View File

@ -0,0 +1,41 @@
TWIP_Steel_FeMnC:
lattice: cF
mechanics:
elasticity: {type: hooke, C_11: 175.0e9, C_12: 115.0e9, C_44: 135.0e9}
plasticity:
type: dislotwin
output: [rho_mob, rho_dip, gamma_sl, Lambda_sl, tau_pass, f_tw, Lambda_tw, tau_hat_tw, f_tr]
D: 2.0e-5
N_sl: [12]
b_sl: [2.56e-10]
rho_mob_0: [1.0e12]
rho_dip_0: [1.0]
v_0: [1.0e4]
Q_s: [3.7e-19]
p_sl: [1.0]
q_sl: [1.0]
tau_0: [1.5e8]
i_sl: [10.0] # Adj. parameter controlling dislocation mean free path
D_0: 4.0e-5 # Vacancy diffusion prefactor / m^2/s
D_a: 1.0 # minimum dipole distance / b
Q_cl: 4.5e-19 # Activation energy for climb / J
h_sl_sl: [0.122, 0.122, 0.625, 0.07, 0.137, 0.122] # Interaction coefficients (Kubin et al. 2008)
# shear band parameters
xi_sb: 180.0e6
Q_sb: 3.7e-19
p_sb: 1.0
q_sb: 1.0
v_sb: 0.0 # set to 0, to turn it off
# twinning parameters
N_tw: [12]
b_tw: [1.47e-10] # Burgers vector length of twin system / b
t_tw: [5.0e-8] # Twin stack mean thickness / m
L_tw: 442.0 # Length of twin nuclei / b
x_c_tw: 1.0e-9 # critical distance for formation of twin nucleus / m
V_cs: 1.67e-29 # cross slip volume / m^3
p_tw: [10.0] # r-exponent in twin formation probability
i_tw: 1.0 # Adj. parameter controlling twin mean free path
h_sl_tw: [0.0, 1.0, 1.0] # dislocation-twin interaction coefficients
h_tw_tw: [0.0, 1.0] # twin-twin interaction coefficients
Gamma_sf_0K: -0.0396 # stacking fault energy / J/m^2 at zero K; TWIP steel: -0.0526; Cu: -0.0396
dGamma_sf_dT: 0.0002 # temperature dependence / J/(m^2 K) of stacking fault energy

View File

@ -1,36 +0,0 @@
[Tungsten]
elasticity hooke
plasticity dislotwin
### Material parameters ###
lattice_structure bcc
C11 523.0e9 # From Marinica et al. Journal of Physics: Condensed Matter(2013)
C12 202.0e9
C44 161.0e9
grainsize 2.0e-5 # Average grain size [m]
SolidSolutionStrength 1.5e8 # Strength due to elements in solid solution
### Dislocation glide parameters ###
#per family
Nslip 12
slipburgers 2.72e-10 # Burgers vector of slip system [m]
rhoedge0 1.0e12 # Initial edge dislocation density [m/m**3]
rhoedgedip0 1.0 # Initial edged dipole dislocation density [m/m**3]
v0 1.0e-4 # Initial glide velocity [m/s]
Qedge 2.725e-19 # Activation energy for dislocation glide [J]
p_slip 0.78 # p-exponent in glide velocity
q_slip 1.58 # q-exponent in glide velocity
tau_peierls 2.03e9 # peierls stress (for bcc)
dipoleformationfactor 0 # to have hardening due to dipole formation off
#hardening
CLambdaSlip 10.0 # Adj. parameter controlling dislocation mean free path
D0 4.0e-5 # Vacancy diffusion prefactor [m**2/s]
Qsd 4.5e-19 # Activation energy for climb [J]
Catomicvolume 1.0 # Adj. parameter controlling the atomic volume [in b]
Cedgedipmindistance 1.0 # Adj. parameter controlling the minimum dipole distance [in b]
interaction_slipslip 1 1 1.4 1.4 1.4 1.4

View File

@ -0,0 +1,21 @@
Tungsten:
lattice: cI
mechanics:
elasticity: {type: hooke, C_11: 523.0e9, C_12: 202.0e9, C_44: 161.0e9} # Marinica et al. Journal of Physics: Condensed Matter(2013)
plasticity:
type: dislotwin
D: 2.0e-5 # Average grain size / m
N_sl: [12]
b_sl: [2.72e-10] # Burgers vector length of slip families / m
rho_mob_0: [1.0e12]
rho_dip_0: [1.0]
v_0: [1.0e4] # Initial glide velocity / m/s
Q_s: [2.725e-19] # Activation energy for dislocation glide / J
p_sl: [0.78] # p-exponent in glide velocity
q_sl: [1.58] # q-exponent in glide velocity
tau_0: [1.5e8] # solid solution strength / Pa
i_sl: [10.0] # Adj. parameter controlling dislocation mean free path
D_0: 4.0e-5 # Vacancy diffusion prefactor / m^2/s
D_a: 1.0 # minimum dipole distance / b
Q_cl: 4.5e-19 # Activation energy for climb / J
h_sl_sl: [1, 1, 1.4, 1.4, 1.4, 1.4]

View File

@ -1,3 +0,0 @@
hydrogenflux_diffusion11 1.0
hydrogenflux_mobility11 1.0
hydrogenVolume 1e-28

View File

@ -1,9 +1,9 @@
# Kuo, J. C., Mikrostrukturmechanik von Bikristallen mit Kippkorngrenzen. Shaker-Verlag 2004. http://edoc.mpg.de/204079
Aluminum:
lattice: aP
mechanics:
lattice: aP
elasticity: {C_11: 110.9e9, C_12: 58.34e9, type: hooke}
output: [F, P, Fe, Fp, Lp]
output: [F, P, F_e, F_p, L_p]
elasticity: {type: hooke, C_11: 110.9e9, C_12: 58.34e9}
plasticity:
type: isotropic
output: [xi]

View File

@ -1,9 +1,8 @@
# Maiti and Eisenlohr 2018 Scripta Materialia
Air:
lattice: aP
mechanics:
lattice: aP
elasticity: {C_11: 10e9, C_12: 0.0, type: hooke}
output: [F, P, Fe, Fp, Lp]
output: [F, P, F_e, F_p, L_p]
elasticity: {type: hooke, C_11: 1e8, C_12: 1e6}
plasticity:
type: isotropic
output: [xi]
@ -14,4 +13,4 @@ Air:
M: 3
h_0: 1e6
a: 2
dilatation: true
dilatation: True

View File

@ -1,21 +0,0 @@
[Aluminum]
elasticity hooke
plasticity phenopowerlaw
(output) resistance_slip
(output) accumulatedshear_slip
lattice_structure fcc
Nslip 12 # per family
c11 106.75e9
c12 60.41e9
c44 28.34e9
gdot0_slip 0.001
n_slip 20
tau0_slip 31e6 # per family
tausat_slip 63e6 # per family
a_slip 2.25
h0_slipslip 75e6
interaction_slipslip 1 1 1.4 1.4 1.4 1.4

View File

@ -0,0 +1,16 @@
Aluminum:
lattice: cF
mechanics:
output: [F, P, F_e, F_p, L_p, O]
elasticity: {C_11: 106.75e9, C_12: 60.41e9, C_44: 28.34e9, type: hooke}
plasticity:
N_sl: [12]
a_sl: 2.25
dot_gamma_0_sl: 0.001
h_0_sl_sl: 75e6
h_sl_sl: [1, 1, 1.4, 1.4, 1.4, 1.4]
n_sl: 20
output: [xi_sl, gamma_sl]
type: phenopowerlaw
xi_0_sl: [31e6]
xi_inf_sl: [63e6]

View File

@ -2,8 +2,8 @@
# Tasan et.al. 2015 International Journal of Plasticity
# Diehl et.al. 2015 Meccanica
Ferrite:
lattice: cI
mechanics:
lattice: cI
elasticity: {C_11: 233.3e9, C_12: 135.5e9, C_44: 118.0e9, type: hooke}
plasticity:
N_sl: [12, 12]

View File

@ -2,8 +2,8 @@
# Tasan et.al. 2015 International Journal of Plasticity
# Diehl et.al. 2015 Meccanica
Martensite:
lattice: cI
mechanics:
lattice: cI
elasticity: {C_11: 417.4e9, C_12: 242.4e9, C_44: 211.1e9, type: hooke}
plasticity:
N_sl: [12, 12]

View File

@ -1,27 +0,0 @@
# parameters fitted by D. Ma to:
# I. Kovács, G. Vörös
# On the mathematical description of the tensile stress-strain curves of polycrystalline face centered cubic metals
# International Journal of Plasticity, Volume 12, Issue 1, 1996, Pages 3543
# DOI: 10.1016/S0749-6419(95)00043-7
[gold_phenopowerlaw]
elasticity hooke
plasticity phenopowerlaw
(output) resistance_slip
lattice_structure fcc
Nslip 12 # per family
c11 191.0e9
c12 162.0e9
c44 42.20e9
gdot0_slip 0.001
n_slip 83.3
tau0_slip 26.25e6 # per family
tausat_slip 53.00e6 # per family
a_slip 1.0
h0_slipslip 75e6
interaction_slipslip 1 1 1.4 1.4 1.4 1.4

View File

@ -0,0 +1,21 @@
# parameters fitted by D. Ma to:
# On the mathematical description of the tensile stress-strain curves of polycrystalline face centered cubic metals
# International Journal of Plasticity, Volume 12, Issue 1, 1996, Pages 35-43
# DOI: 10.1016/S0749-6419(95)00043-7
Gold:
lattice: cF
mechanics:
output: [F, P, F_e, F_p, L_p, O]
elasticity: {type: hooke, C_11: 191e9, C_12: 162e9, C_44: 42.2e9}
plasticity:
type: phenopowerlaw
output: [xi_sl]
N_sl: [12]
n_sl: 83
dot_gamma_0_sl: 0.001
h_0_sl_sl: 75e6
h_sl_sl: [1, 1, 1.4, 1.4, 1.4, 1.4]
a_sl: 1.0
xi_0_sl: [26e6]
xi_inf_sl: [53e6]

View File

@ -1,56 +0,0 @@
#-------------------#
<phase>
#-------------------#
/echo/
[Mg]
plasticity phenopowerlaw
elasticity hooke
(output) resistance_slip
(output) resistance_twin
lattice_structure hex
c/a 1.62350 # from Tromans 2011, Elastic Anisotropy of HCP Metal Crystals and Polycrystals
c11 59.3e9 # - " -
c33 61.5e9 # - " -
c44 16.4e9 # - " -
c12 25.7e9 # - " -
c13 21.4e9 # - " -
# basal prism prism pyr(a) pyr(c+a) pyr(c+a)
Nslip 3 3 0 6 0 6 # from Agnew et al 2006, Validating a polycrystal model for the elastoplastic response of mg alloy AZ32 using in situ neutron diffraction
# T1 C1 T2 C2
Ntwin 6 0 0 6 # - " -
# basal prism prism pyr(a) pyr(c+a) pyr(c+a)
tau0_slip 10.0e6 55.0e6 0 60.0e6 0.0 60.0e6 # - " - table 1, pyr(a) set to pyr(c+a)
tausat_slip 40.0e6 135.0e6 0 150.0e6 0.0 150.0e6 # - " - table 1, pyr(a) set to pyr(c+a)
# T1 C1 T2 C2
tau0_twin 40e6 0.0 0.0 60.0e6 # - " - table 1, compressive twin guessed by Steffi, tensile twin modified to match experimental results
h0_twintwin 50.0e6 # - " - table 1, same range as theta_0
h0_slipslip 500.0e6 # - " - table 1, same range as theta_0
h0_twinslip 150.0e6 # guessing
interaction_slipslip 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 # just guessing
interaction_twintwin 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 # - " -
interaction_sliptwin 1 1 1 1 1 1 1 1 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 1 1 1 1 1 1 1 1 # - " -
####################################################
# open for discussion
####################################################
n_twin 20
n_slip 20
gdot0_twin 0.001
gdot0_slip 0.001
twin_b 0
twin_c 0
twin_d 20
twin_e 20
a_slip 2.25
s_pr 10.0 # push-up factor for slip saturation due to twinning

View File

@ -0,0 +1,31 @@
# Tromans 2011, Elastic Anisotropy of HCP Metal Crystals and Polycrystals
Magnesium:
lattice: hP
c/a: 1.62350
mechanics:
output: [F, P, F_e, F_p, L_p, O]
elasticity: {C_11: 59.3e9, C_12: 25.7e9, C_13: 21.4e9, C_33: 61.5e9, C_44: 16.4e9, type: hooke}
plasticity:
N_sl: [3, 3, 0, 6, 0, 6]
N_tw: [6, 0, 0, 6]
h_0_tw_tw: 50.0e6
h_0_sl_sl: 500.0e6
h_0_tw_sl: 150.0e6
h_sl_sl: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
h_tw_tw: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
h_sl_tw: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
h_tw_sl: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
output: [xi_sl, xi_tw]
type: phenopowerlaw
xi_0_sl: [10.0e6, 55.0e6, 0, 60.0e6, 0.0, 60.0e6]
xi_inf_sl: [40.0e6, 135.0e6, 0, 150.0e6, 0.0, 150.0e6]
xi_0_tw: [40e6, 0.0, 0.0, 60.0e6]
####################################################
# open for discussion
####################################################
a_sl: 2.25
dot_gamma_0_sl: 0.001
dot_gamma_0_tw: 0.001
n_sl: 20
n_tw: 20
f_sl_sat_tw: 10.0

View File

@ -1,23 +0,0 @@
[cpTi-alpha]
plasticity phenopowerlaw
elasticity hooke
lattice_structure hex
covera_ratio 1.587
# M. Levy, Handbook of Elastic Properties of Solids, Liquids, and Gases (2001)
c11 160.0e9
c12 90.0e9
c13 66.0e9
c33 181.7e9
c44 46.5e9
# C. Zambaldi, "Orientation informed nanoindentation of a-titanium: Indentation pileup in hexagonal metals deforming by prismatic slip", J. Mater. Res., Vol. 27, No. 1, Jan 14, 2012
gdot0_slip 0.001
n_slip 20
nslip 3 3 0 6
tau0_slip 349.3e6 150e6 0 1107.9e6
tausat_slip 568.6e6 1502.2e6 0 3420.1e6
a_slip 2
h0_slipslip 15e6
interaction_slipslip 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

View File

@ -0,0 +1,20 @@
# M. Levy, Handbook of Elastic Properties of Solids, Liquids, and Gases (2001)
# C. Zambaldi, "Orientation informed nanoindentation of a-titanium: Indentation pileup in hexagonal metals deforming by prismatic slip", J. Mater. Res., Vol. 27, No. 1, Jan 14, 2012
# Better use values from L. Wang, Z. Zheng, H. Phukan, P. Kenesei, J.-S. Park, J. Lind, R.M. Suter, T.R. Bieler, Direct measurement of critical resolved shear stress of prismatic and basal slip in polycrystalline Ti using high energy X-ray diffraction microscopy, Acta Mater 2017
cpTi:
lattice: hP
c/a: 1.587
mechanics:
output: [F, P, F_e, F_p, L_p, O]
elasticity: {C_11: 160.0e9, C_12: 90.0e9, C_13: 66.0e9, C_33: 181.7e9, C_44: 46.5e9, type: hooke}
plasticity:
N_sl: [3, 3, 0, 6, 12]
a_sl: 2.0
dot_gamma_0_sl: 0.001
h_0_sl_sl: 200e6
h_sl_sl: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
n_sl: 20
output: [gamma_sl]
type: phenopowerlaw
xi_0_sl: [0.15e9, 0.09e9, 0, 0.20e9, 0.25e9]
xi_inf_sl: [0.24e9, 0.5e9, 0, 0.6e9, 0.8e9]

View File

@ -1,2 +0,0 @@
[001]
(gauss) phi1 0.000 Phi 0.000 phi2 0.000

View File

@ -1,2 +0,0 @@
[101]
(gauss) phi1 0.000 Phi 45.000 phi2 90.000

View File

@ -1,2 +0,0 @@
[111]
(gauss) phi1 0.000 Phi 54.7356 phi2 45.000

View File

@ -1,2 +0,0 @@
[123]
(gauss) phi1 209.805 Phi 29.206 phi2 63.435

View File

@ -1,20 +0,0 @@
# The material.config file needs to specify five parts:
# homogenization, microstructure, crystallite, phase, and texture.
# You can either put the full text in here or include suited separate files
<homogenization>
{./Homogenization_Isostrain_SX.config}
<microstructure>
[one_only]
crystallite 1
(constituent) phase 1 texture 1 fraction 1.0
<crystallite>
{./Crystallite_All.config}
<phase>
{./Phase_Phenopowerlaw_Aluminum.config}
<texture>
{./Texture_Gauss_001.config}

View File

@ -1,9 +0,0 @@
step:
- mechanics:
dot_F: [0, 0, 0,
1e-3, 0, 0,
0, 0, 0]
discretization:
t: 60
N: 120
f_out: 20

View File

@ -1,10 +0,0 @@
---
step:
- mechanics:
dot_F: [0, 0, 1e-3,
0, 0, 0,
0, 0, 0]
discretization:
t: 60
N: 120
f_out: 20

View File

@ -1,25 +0,0 @@
---
step:
- mechanics:
dot_F: [1.0e-3, 0, 0,
0, x, 0,
0, 0, x]
P: [x, x, x,
x, 0, x,
x, x, 0]
discretization:
t: 10
N: 40
f_out: 4
- mechanics:
dot_F: [1.0e-3, 0, 0,
0, x, 0,
0, 0, x]
P: [x, x, x,
x, 0, x,
x, x, 0]
discretization:
t: 60
N: 60
f_out: 4

View File

@ -2,108 +2,108 @@
homogenization:
SX:
N_constituents: 1
mechanics: {type: none}
mechanics: {type: pass}
material:
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [1.0, 0.0, 0.0, 0.0]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.7936696712125002, -0.28765777461664166, -0.3436487135089419, 0.4113964260949434]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.3986143167493579, -0.7014883552495493, 0.2154871765709027, 0.5500781677772945]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.28645844315788244, -0.022571491243423537, -0.467933059311115, -0.8357456192708106]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.33012772942625784, -0.6781865350268957, 0.6494525351030648, 0.09638521992649676]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.43596817439583935, -0.5982537129781701, 0.046599032277502436, 0.6707106499919265]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.169734823419553, -0.699615227367322, -0.6059581215838098, -0.33844257746495854]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.9698864809294915, 0.1729052643205874, -0.15948307917616958, 0.06315956884687175]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.46205660912967883, 0.3105054068891252, -0.617849551030653, 0.555294529545738]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.4512443497461787, -0.7636045534540555, -0.04739348426715133, -0.45939142396805815]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.2161856212656443, -0.6581450184826598, -0.5498086209601588, 0.4667112513346289]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.8753220715350803, -0.4561599367657419, -0.13298279533852678, -0.08969369719975541]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.11908260752431069, 0.18266024809834172, -0.7144822594012615, -0.664807992845101]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.751104669484278, 0.5585633382623958, -0.34579336397009175, 0.06538900566860861]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.08740438971703973, 0.8991264096610437, -0.4156704205935976, 0.10559485570696363]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.5584325870096193, 0.6016408353068798, -0.14280340445801173, 0.5529814994483859]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.4052725440888093, 0.25253073423599154, 0.5693263597910454, -0.669215876471182]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.7570164606888676, 0.15265448024694664, -0.5998021466848317, 0.20942796551297105]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.6987659297138081, -0.132172211261028, -0.19693254724422338, 0.6748883269678543]
- homogenization: SX
constituents:
- phase: Aluminum
fraction: 1.0
v: 1.0
O: [0.7729330445886478, 0.21682179052722322, -0.5207379472917645, 0.2905078484066341]
phase:

View File

@ -0,0 +1,15 @@
---
solver:
mechanical: spectral_basic
loadstep:
- boundary_conditions:
mechanical:
dot_F: [0, 0, 0,
1e-3, 0, 0,
0, 0, 0]
discretization:
t: 60
N: 120
f_out: 20

View File

@ -0,0 +1,15 @@
---
solver:
mechanical: spectral_basic
loadstep:
- boundary_conditions:
mechanical:
dot_F: [0, 0, 1e-3,
0, 0, 0,
0, 0, 0]
discretization:
t: 60
N: 120
f_out: 20

View File

@ -0,0 +1,30 @@
---
solver:
mechanical: spectral_basic
loadstep:
- boundary_conditions:
mechanical:
dot_F: [1.0e-3, 0, 0,
0, x, 0,
0, 0, x]
P: [x, x, x,
x, 0, x,
x, x, 0]
discretization:
t: 10
N: 40
f_out: 4
- boundary_conditions:
mechanical:
dot_F: [1.0e-3, 0, 0,
0, x, 0,
0, 0, x]
P: [x, x, x,
x, 0, x,
x, x, 0]
discretization:
t: 60
N: 60
f_out: 4

View File

@ -5,13 +5,9 @@ import glob
import argparse
from pathlib import Path
import damask
msc_version = float(damask.environment.options['MSC_VERSION'])
if int(msc_version) == msc_version:
msc_version = int(msc_version)
msc_root = Path(damask.environment.options['MSC_ROOT'])
damask_root = damask.environment.root_dir
msc_version = os.environ['MSC_VERSION']
msc_root = Path(os.environ['MSC_ROOT'])
damask_root = Path(os.environ['DAMASK_ROOT'])
parser = argparse.ArgumentParser(
description='Apply DAMASK modification to MSC.Marc/Mentat',
@ -24,7 +20,7 @@ def copy_and_replace(in_file,dst):
with open(in_file) as f:
content = f.read()
content = content.replace('%INSTALLDIR%',str(msc_root))
content = content.replace('%VERSION%',str(msc_version))
content = content.replace('%VERSION%', msc_version)
content = content.replace('%EDITOR%', parser.parse_args().editor)
with open(dst/Path(in_file).name,'w') as f:
f.write(content)
@ -53,8 +49,8 @@ for in_file in glob.glob(str(src/'job_run.ms')):
print('compiling Mentat menu binaries...')
executable = str(msc_root/f'mentat{msc_version}/bin/mentat')
menu_file = str(msc_root/f'mentat{msc_version}/menus/linux64/main.msb')
executable = msc_root/f'mentat{msc_version}/bin/mentat'
menu_file = msc_root/f'mentat{msc_version}/menus/linux64/main.msb'
os.system(f'xvfb-run {executable} -compile {menu_file}')

View File

@ -3,11 +3,9 @@
# Makes postprocessing routines accessible from everywhere.
import sys
from pathlib import Path
import os
import damask
env = damask.Environment()
bin_dir = env.root_dir/Path('bin')
bin_dir = Path(os.environ['DAMASK_ROOT'])/'bin'
if not bin_dir.exists():
bin_dir.mkdir()
@ -15,7 +13,7 @@ if not bin_dir.exists():
sys.stdout.write('\nsymbolic linking...\n')
for sub_dir in ['pre','post']:
the_dir = env.root_dir/Path('processing')/Path(sub_dir)
the_dir = Path(os.environ['DAMASK_ROOT'])/'processing'/sub_dir
for the_file in the_dir.glob('*.py'):
src = the_dir/the_file

View File

@ -41,15 +41,15 @@ for filename in options.filenames:
table = damask.Table(np.ones(np.product(results.cells),dtype=int)*int(inc[3:]),{'inc':(1,)})\
.add('pos',coords.reshape(-1,3))
results.pick('homogenizations',False)
results.pick('phases',True)
results.view('homogenizations',False)
results.view('phases',True)
for label in options.con:
x = results.get_dataset_location(label)
if len(x) != 0:
table = table.add(label,results.read_dataset(x,0,plain=True).reshape(results.cells.prod(),-1))
results.pick('phases',False)
results.pick('homogenizations',True)
results.view('phases',False)
results.view('homogenizations',True)
for label in options.mat:
x = results.get_dataset_location(label)
if len(x) != 0:

View File

@ -16,8 +16,6 @@ with open(_Path(__file__).parent/_Path('VERSION')) as _f:
__version__ = version
# make classes directly accessible as damask.Class
from ._environment import Environment as _ # noqa
environment = _()
from . import util # noqa
from . import seeds # noqa
from . import tensor # noqa
@ -38,7 +36,6 @@ from ._result import Result # noqa
# deprecated
Environment = _
from ._asciitable import ASCIItable # noqa
from ._test import Test # noqa
from .util import extendableOption # noqa

View File

@ -223,25 +223,46 @@ class Colormap(mpl.colors.ListedColormap):
return Colormap(np.array(rev.colors),rev.name[:-4] if rev.name.endswith('_r_r') else rev.name)
def _get_file_handle(self,fname,extension):
"""
Provide file handle.
Parameters
----------
fname : file, str, pathlib.Path, or None
Filename or filehandle, will be name of the colormap+extension if None.
extension: str
Extension of the filename.
Returns
-------
f
File handle
"""
if fname is None:
fhandle = open(self.name.replace(' ','_')+'.'+extension,'w',newline='\n')
else:
try:
fhandle = open(fname,'w',newline='\n')
except TypeError:
fhandle = fname
return fhandle
def save_paraview(self,fname=None):
"""
Save as JSON file for use in Paraview.
Parameters
----------
fname : file, str, or pathlib.Path, optional.
fname : file, str, or pathlib.Path, optional
Filename to store results. If not given, the filename will
consist of the name of the colormap and extension '.json'.
"""
if fname is None:
fhandle = None
else:
try:
fhandle = open(fname,'w')
except TypeError:
fhandle = fname
colors = []
for i,c in enumerate(np.round(self.colors,6).tolist()):
colors+=[i]+c
@ -254,8 +275,7 @@ class Colormap(mpl.colors.ListedColormap):
'RGBPoints':colors
}]
with open(self.name.replace(' ','_')+'.json', 'w') if fhandle is None else fhandle as f:
json.dump(out, f,indent=4)
json.dump(out,self._get_file_handle(fname,'json'),indent=4)
def save_ASCII(self,fname=None):
@ -264,24 +284,14 @@ class Colormap(mpl.colors.ListedColormap):
Parameters
----------
fname : file, str, or pathlib.Path, optional.
fname : file, str, or pathlib.Path, optional
Filename to store results. If not given, the filename will
consist of the name of the colormap and extension '.txt'.
"""
if fname is None:
fhandle = None
else:
try:
fhandle = open(fname,'w')
except TypeError:
fhandle = fname
labels = {'RGBA':4} if self.colors.shape[1] == 4 else {'RGB': 3}
t = Table(self.colors,labels,f'Creator: {util.execution_stamp("Colormap")}')
with open(self.name.replace(' ','_')+'.txt', 'w') if fhandle is None else fhandle as f:
t.save(f)
t.save(self._get_file_handle(fname,'txt'))
def save_GOM(self,fname=None):
@ -290,26 +300,19 @@ class Colormap(mpl.colors.ListedColormap):
Parameters
----------
fname : file, str, or pathlib.Path, optional.
fname : file, str, or pathlib.Path, optional
Filename to store results. If not given, the filename will
consist of the name of the colormap and extension '.legend'.
"""
if fname is None:
fhandle = None
else:
try:
fhandle = open(fname,'w')
except TypeError:
fhandle = fname
# ToDo: test in GOM
GOM_str = '1 1 {name} 9 {name} '.format(name=self.name.replace(" ","_")) \
+ '0 1 0 3 0 0 -1 9 \\ 0 0 0 255 255 255 0 0 255 ' \
+ f'30 NO_UNIT 1 1 64 64 64 255 1 0 0 0 0 0 0 3 0 {len(self.colors)}' \
+ ' '.join([f' 0 {c[0]} {c[1]} {c[2]} 255 1' for c in reversed((self.colors*255).astype(int))]) \
+ '\n'
with open(self.name.replace(' ','_')+'.legend', 'w') if fhandle is None else fhandle as f:
f.write(GOM_str)
self._get_file_handle(fname,'legend').write(GOM_str)
def save_gmsh(self,fname=None):
@ -318,24 +321,16 @@ class Colormap(mpl.colors.ListedColormap):
Parameters
----------
fname : file, str, or pathlib.Path, optional.
fname : file, str, or pathlib.Path, optional
Filename to store results. If not given, the filename will
consist of the name of the colormap and extension '.msh'.
"""
if fname is None:
fhandle = None
else:
try:
fhandle = open(fname,'w')
except TypeError:
fhandle = fname
# ToDo: test in gmsh
gmsh_str = 'View.ColorTable = {\n' \
+'\n'.join([f'{c[0]},{c[1]},{c[2]},' for c in self.colors[:,:3]*255]) \
+'\n}\n'
with open(self.name.replace(' ','_')+'.msh', 'w') if fhandle is None else fhandle as f:
f.write(gmsh_str)
self._get_file_handle(fname,'msh').write(gmsh_str)
@staticmethod

View File

@ -1,4 +1,6 @@
import copy
from io import StringIO
from collections.abc import Iterable
import abc
import numpy as np
@ -35,6 +37,50 @@ class Config(dict):
output.seek(0)
return ''.join(output.readlines())
def __copy__(self):
"""Create deep copy."""
return copy.deepcopy(self)
copy = __copy__
def __or__(self,other):
"""
Update configuration with contents of other.
Parameters
----------
other : damask.Config or dict
Key-value pairs that update self.
"""
duplicate = self.copy()
duplicate.update(other)
return duplicate
def __ior__(self,other):
"""Update configuration with contents of other."""
return self.__or__(other)
def delete(self,keys):
"""
Remove configuration keys.
Parameters
----------
keys : iterable or scalar
Label of the key(s) to remove.
"""
duplicate = self.copy()
for k in keys if isinstance(keys, Iterable) and not isinstance(keys, str) else [keys]:
del duplicate[k]
return duplicate
@classmethod
def load(cls,fname):
"""
@ -52,6 +98,7 @@ class Config(dict):
fhandle = fname
return cls(yaml.safe_load(fhandle))
def save(self,fname,**kwargs):
"""
Save to yaml file.
@ -65,7 +112,7 @@ class Config(dict):
"""
try:
fhandle = open(fname,'w')
fhandle = open(fname,'w',newline='\n')
except TypeError:
fhandle = fname
@ -95,6 +142,7 @@ class Config(dict):
"""Check for completeness."""
pass
@property
@abc.abstractmethod
def is_valid(self):

View File

@ -1,4 +1,3 @@
import copy
from os import path
import numpy as np
@ -7,6 +6,7 @@ import h5py
from . import Config
from . import Rotation
from . import Orientation
from . import util
class ConfigMaterial(Config):
"""Material configuration."""
@ -15,11 +15,10 @@ class ConfigMaterial(Config):
'homogenization': {},
'phase': {}}
def __init__(self,d={}):
def __init__(self,d=_defaults):
"""Initialize object with default dictionary keys."""
super().__init__(d)
for k,v in self._defaults.items():
if k not in self: self[k] = v
def save(self,fname='material.yaml',**kwargs):
"""
@ -51,7 +50,7 @@ class ConfigMaterial(Config):
@staticmethod
def from_table(table,constituents={},**kwargs):
def from_table(table,**kwargs):
"""
Load from an ASCII table.
@ -59,12 +58,9 @@ class ConfigMaterial(Config):
----------
table : damask.Table
Table that contains material information.
constituents : dict, optional
Entries for 'constituents'. The key is the name and the value specifies
the label of the data column in the table
**kwargs
Keyword arguments where the key is the name and the value specifies
the label of the data column in the table
Keyword arguments where the key is the name and the value specifies
the label of the data column in the table.
Examples
--------
@ -75,32 +71,30 @@ class ConfigMaterial(Config):
pos pos pos qu qu qu qu phase homog
0 0 0 0 0.19 0.8 0.24 -0.51 Aluminum SX
1 1 0 0 0.8 0.19 0.24 -0.51 Steel SX
>>> cm.from_table(t,{'O':'qu','phase':'phase'},homogenization='homog')
1 1 1 0 0.8 0.19 0.24 -0.51 Steel SX
>>> cm.from_table(t,O='qu',phase='phase',homogenization='homog')
material:
- constituents:
- O: [0.19, 0.8, 0.24, -0.51]
fraction: 1.0
v: 1.0
phase: Aluminum
homogenization: SX
- constituents:
- O: [0.8, 0.19, 0.24, -0.51]
fraction: 1.0
v: 1.0
phase: Steel
homogenization: SX
homogenization: {}
phase: {}
"""
constituents_ = {k:table.get(v) for k,v in constituents.items()}
kwargs_ = {k:table.get(v) for k,v in kwargs.items()}
_,idx = np.unique(np.hstack(list({**constituents_,**kwargs_}.values())),return_index=True,axis=0)
_,idx = np.unique(np.hstack(list(kwargs_.values())),return_index=True,axis=0)
idx = np.sort(idx)
constituents_ = {k:np.atleast_1d(v[idx].squeeze()) for k,v in constituents_.items()}
kwargs_ = {k:np.atleast_1d(v[idx].squeeze()) for k,v in kwargs_.items()}
kwargs_ = {k:np.atleast_1d(v[idx].squeeze()) for k,v in kwargs_.items()}
return ConfigMaterial().material_add(constituents_,**kwargs_)
return ConfigMaterial().material_add(**kwargs_)
@staticmethod
@ -108,11 +102,11 @@ class ConfigMaterial(Config):
r"""
Load material data from DREAM3D file.
The parts of homogenization and phase need to be added by the user.
The parts of homogenization and phase need to be added by the user.
Parameters
----------
fname : str
fname : str
path to the DREAM3D file.
base_group : str
Name of the group (folder) below 'DataContainers',
@ -126,7 +120,7 @@ class ConfigMaterial(Config):
phase_id : str
Name of the dataset containing phase IDs for each grain,
for example 'Phases'.
phase_name : list
phase_name : list
List with name of the phases.
Examples
@ -135,25 +129,25 @@ class ConfigMaterial(Config):
>>> import damask
>>> import damask.ConfigMaterial as cm
>>> cm.load_from_Dream3D('20grains16x16x16.dream3D','SyntheticVolumeDataContainer', 'Grain Data'\
'EulerAngles','Phases',['Ferrite'])
'EulerAngles','Phases',['Ferrite'])
for point based data with single phase
>>> import damask
>>> import damask.ConfigMaterial as cm
>>> cm.load_from_Dream3D('20grains16x16x16.dream3D','SyntheticVolumeDataContainer', 'CellData'\
'EulerAngles','Phases',['Ferrite'])
'EulerAngles','Phases',['Ferrite'])
for grain based data with dual phase
>>> import damask
>>> import damask.ConfigMaterial as cm
>>> cm.load_from_Dream3D('20grains16x16x16.dream3D','SyntheticVolumeDataContainer', 'Grain Data'\
'EulerAngles','Phases',['Ferrite','Martensite'])
'EulerAngles','Phases',['Ferrite','Martensite'])
for point based data with dual phase
>>> import damask
>>> import damask.ConfigMaterial as cm
>>> cm.load_from_Dream3D('20grains16x16x16.dream3D','SyntheticVolumeDataContainer', 'CellData'\
'EulerAngles','Phases',['Ferrite','Martensite'])
'EulerAngles','Phases',['Ferrite','Martensite'])
"""
root_dir = 'DataContainers'
@ -162,13 +156,13 @@ class ConfigMaterial(Config):
config_info = ConfigMaterial() # empty yaml dictionary
orientation_path = path.join(root_dir,base_group,data_group,ori_data)
orientation_path = path.join(root_dir,base_group,data_group,ori_data)
if hdf[orientation_path].attrs['TupleDimensions'].shape == (3,):
grain_orientations = np.array(hdf[orientation_path]).reshape(cells.prod(),3,order='F')
else:
grain_orientations = np.array(hdf[orientation_path])[1:]
grain_quats = Rotation.from_Euler_angles(grain_orientations).as_quaternion()
grain_quats = Rotation.from_Euler_angles(grain_orientations).as_quaternion()
phase_path = path.join(root_dir,base_group,data_group,phase_id)
if hdf[phase_path].attrs['TupleDimensions'].shape == (3,):
@ -181,13 +175,12 @@ class ConfigMaterial(Config):
material_dict = config_info.material_add(constituents={'phase':phase_name_list,'O':grain_quats},homogenization='SX')
material_dict.save()
@property
def is_complete(self):
"""Check for completeness."""
ok = True
for top_level in ['homogenization','phase','material']:
# ToDo: With python 3.8 as prerequisite we can shorten with :=
ok &= top_level in self
if top_level not in self: print(f'{top_level} entry missing')
@ -238,7 +231,7 @@ class ConfigMaterial(Config):
@property
def is_valid(self):
"""Check for valid file layout."""
"""Check for valid content."""
ok = True
if 'phase' in self:
@ -247,25 +240,23 @@ class ConfigMaterial(Config):
try:
Orientation(lattice=v['lattice'])
except KeyError:
s = v['lattice']
print(f"Invalid lattice: '{s}' in phase '{k}'")
print(f"Invalid lattice '{v['lattice']}' in phase '{k}'")
ok = False
if 'material' in self:
for i,v in enumerate(self['material']):
if 'constituents' in v:
f = 0.0
for c in v['constituents']:
f+= float(c['fraction'])
for i,m in enumerate(self['material']):
if 'constituents' in m:
v = 0.0
for c in m['constituents']:
v += float(c['v'])
if 'O' in c:
try:
Rotation.from_quaternion(c['O'])
except ValueError:
o = c['O']
print(f"Invalid orientation: '{o}' in material '{i}'")
print(f"Invalid orientation '{c['O']}' in material '{i}'")
ok = False
if not np.isclose(f,1.0):
print(f"Invalid total fraction '{f}' in material '{i}'")
if not np.isclose(v,1.0):
print(f"Total fraction v = {v} ≠ 1 in material '{i}'")
ok = False
return ok
@ -284,10 +275,15 @@ class ConfigMaterial(Config):
constituent: list of ints, optional
Limit renaming to selected constituents.
Returns
-------
cfg : damask.ConfigMaterial
Updated material configuration.
"""
dup = copy.deepcopy(self)
dup = self.copy()
for i,m in enumerate(dup['material']):
if ID and i not in ID: continue
if ID is not None and i not in ID: continue
for c in m['constituents']:
if constituent is not None and c not in constituent: continue
try:
@ -308,10 +304,15 @@ class ConfigMaterial(Config):
ID: list of ints, optional
Limit renaming to selected homogenization IDs.
Returns
-------
cfg : damask.ConfigMaterial
Updated material configuration.
"""
dup = copy.deepcopy(self)
dup = self.copy()
for i,m in enumerate(dup['material']):
if ID and i not in ID: continue
if ID is not None and i not in ID: continue
try:
m['homogenization'] = mapping[m['homogenization']]
except KeyError:
@ -319,93 +320,92 @@ class ConfigMaterial(Config):
return dup
def material_add(self,constituents=None,**kwargs):
def material_add(self,**kwargs):
"""
Add material entries.
Parameters
----------
constituents : dict, optional
Entries for 'constituents' as key-value pair.
**kwargs
Key-value pairs.
Returns
-------
cfg : damask.ConfigMaterial
Updated material configuration.
Examples
--------
>>> import numpy as np
>>> import damask
>>> O = damask.Rotation.from_random(3).as_quaternion()
>>> phase = ['Aluminum','Steel','Aluminum']
>>> m = damask.ConfigMaterial().material_add(constituents={'phase':phase,'O':O},
... homogenization='SX')
>>> m = damask.ConfigMaterial().material_add(phase = ['Aluminum','Steel'],
... O = damask.Rotation.from_random(2),
... homogenization = 'SX')
>>> m
material:
- constituents:
- O: [0.577764, -0.146299, -0.617669, 0.513010]
fraction: 1.0
v: 1.0
phase: Aluminum
homogenization: SX
- constituents:
- O: [0.184176, 0.340305, 0.737247, 0.553840]
fraction: 1.0
v: 1.0
phase: Steel
homogenization: SX
- constituents:
- O: [0.0886257, -0.144848, 0.615674, -0.769487]
fraction: 1.0
phase: Aluminum
homogenization: SX
homogenization: {}
phase: {}
>>> m = damask.ConfigMaterial().material_add(phase = np.array(['Austenite','Martensite']).reshape(1,2),
... O = damask.Rotation.from_random((2,2)),
... v = np.array([0.2,0.8]).reshape(1,2),
... homogenization = ['A','B'])
>>> m
material:
- constituents:
- phase: Austenite
O: [0.659802978293224, 0.6953785848195171, 0.22426295326327111, -0.17554139512785227]
v: 0.2
- phase: Martensite
O: [0.49356745891301596, 0.2841806579193434, -0.7487679215072818, -0.339085707289975]
v: 0.8
homogenization: A
- constituents:
- phase: Austenite
O: [0.26542221365204055, 0.7268854930702071, 0.4474726435701472, -0.44828201137283735]
v: 0.2
- phase: Martensite
O: [0.6545817158479885, -0.08004812803625233, -0.6226561293931374, 0.4212059104577611]
v: 0.8
homogenization: B
homogenization: {}
phase: {}
"""
length = -1
for v in kwargs.values():
if hasattr(v,'__len__') and not isinstance(v,str):
if length != -1 and len(v) != length:
raise ValueError('Cannot add entries of different length')
else:
length = len(v)
length = max(1,length)
c = [{} for _ in range(length)] if constituents is None else \
[{'constituents':u} for u in ConfigMaterial._constituents(**constituents)]
if len(c) == 1: c = [copy.deepcopy(c[0]) for _ in range(length)]
if length != 1 and length != len(c):
raise ValueError('Cannot add entries of different length')
N,n,shaped = 1,1,{}
for k,v in kwargs.items():
if hasattr(v,'__len__') and not isinstance(v,str):
for i,vv in enumerate(v):
c[i][k] = vv.item() if isinstance(vv,np.generic) else vv
else:
for i in range(len(c)):
c[i][k] = v
dup = copy.deepcopy(self)
dup['material'] = dup['material'] + c if 'material' in dup else c
shaped[k] = np.array(v)
s = shaped[k].shape[:-1] if k=='O' else shaped[k].shape
N = max(N,s[0]) if len(s)>0 else N
n = max(n,s[1]) if len(s)>1 else n
mat = [{'constituents':[{} for _ in range(n)]} for _ in range(N)]
if 'v' not in kwargs:
shaped['v'] = np.broadcast_to(1/n,(N,n))
for k,v in shaped.items():
target = (N,n,4) if k=='O' else (N,n)
obj = np.broadcast_to(v.reshape(util.shapeshifter(v.shape,target,mode='right')),target)
for i in range(N):
if k in ['phase','O','v']:
for j in range(n):
mat[i]['constituents'][j][k] = obj[i,j].item() if isinstance(obj[i,j],np.generic) else obj[i,j]
else:
mat[i][k] = obj[i,0].item() if isinstance(obj[i,0],np.generic) else obj[i,0]
dup = self.copy()
dup['material'] = dup['material'] + mat if 'material' in dup else mat
return dup
@staticmethod
def _constituents(N=1,**kwargs):
"""Construct list of constituents."""
N_material=1
for v in kwargs.values():
if hasattr(v,'__len__') and not isinstance(v,str): N_material = len(v)
if N == 1:
m = [[{'fraction':1.0}] for _ in range(N_material)]
for k,v in kwargs.items():
if hasattr(v,'__len__') and not isinstance(v,str):
if len(v) != N_material:
raise ValueError('Cannot add entries of different length')
for i,vv in enumerate(np.array(v)):
m[i][0][k] = vv.item() if isinstance(vv,np.generic) else vv
else:
for i in range(N_material):
m[i][0][k] = v
return m
else:
raise NotImplementedError

View File

@ -1,41 +0,0 @@
import os
from pathlib import Path
class Environment:
@property
def screen_size(self):
try:
import wx
_ = wx.App(False) # noqa
width, height = wx.GetDisplaySize()
except ImportError:
try:
import tkinter
tk = tkinter.Tk()
width = tk.winfo_screenwidth()
height = tk.winfo_screenheight()
tk.destroy()
except Exception as e:
width = 1024
height = 768
return (width,height)
@property
def options(self):
options = {}
for item in ['DAMASK_NUM_THREADS',
'MSC_ROOT',
'MSC_VERSION',
]:
options[item] = os.environ[item] if item in os.environ else None
return options
@property
def root_dir(self):
"""Return DAMASK root path."""
return Path(__file__).parents[2]

View File

@ -1,7 +1,7 @@
import copy
import multiprocessing as mp
from functools import partial
from os import path
import os
import warnings
import numpy as np
@ -10,7 +10,6 @@ import h5py
from scipy import ndimage, spatial
from vtk.util.numpy_support import vtk_to_numpy as vtk_to_np
from . import environment
from . import VTK
from . import util
from . import grid_filters
@ -57,13 +56,10 @@ class Grid:
def __copy__(self):
"""Copy grid."""
"""Create deep copy."""
return copy.deepcopy(self)
def copy(self):
"""Copy grid."""
return self.__copy__()
copy = __copy__
def diff(self,other):
@ -126,7 +122,7 @@ class Grid:
@size.setter
def size(self,size):
if len(size) != 3 or any(np.array(size) <= 0):
if len(size) != 3 or any(np.array(size) < 0):
raise ValueError(f'invalid size {size}')
else:
self._size = np.array(size)
@ -206,7 +202,7 @@ class Grid:
Geometry file to read.
"""
warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.1.0', DeprecationWarning)
warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.1.0', DeprecationWarning,2)
try:
f = open(fname)
except TypeError:
@ -281,14 +277,14 @@ class Grid:
"""
root_dir ='DataContainers'
f = h5py.File(fname, 'r')
g = path.join(root_dir,base_group,'_SIMPL_GEOMETRY')
cells = f[path.join(g,'DIMENSIONS')][()]
size = f[path.join(g,'SPACING')][()] * cells
origin = f[path.join(g,'ORIGIN')][()]
g = os.path.join(root_dir,base_group,'_SIMPL_GEOMETRY')
cells = f[os.path.join(g,'DIMENSIONS')][()]
size = f[os.path.join(g,'SPACING')][()] * cells
origin = f[os.path.join(g,'ORIGIN')][()]
ma = np.arange(cells.prod(),dtype=int) \
if point_data is None else \
np.reshape(f[path.join(root_dir,base_group,point_data,material)],cells.prod())
np.reshape(f[os.path.join(root_dir,base_group,point_data,material)],cells.prod())
return Grid(ma.reshape(cells,order='F'),size,origin,util.execution_stamp('Grid','load_DREAM3D'))
@ -307,7 +303,7 @@ class Grid:
Need to be ordered (1./x fast, 3./z slow).
labels : str or list of str
Label(s) of the columns containing the material definition.
Each unique combintation of values results in one material ID.
Each unique combination of values results in one material ID.
"""
cells,size,origin = grid_filters.cellsSizeOrigin_coordinates0_point(table.get(coordinates))
@ -358,7 +354,7 @@ class Grid:
seeds_p = seeds
coords = grid_filters.coordinates0_point(cells,size).reshape(-1,3)
pool = mp.Pool(processes = int(environment.options['DAMASK_NUM_THREADS']))
pool = mp.Pool(int(os.environ.get('OMP_NUM_THREADS',1)))
result = pool.map_async(partial(Grid._find_closest_seed,seeds_p,weights_p), [coord for coord in coords])
pool.close()
pool.join()
@ -545,7 +541,7 @@ class Grid:
Compress geometry with 'x of y' and 'a to b'.
"""
warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.1.0', DeprecationWarning)
warnings.warn('Support for ASCII-based geom format will be removed in DAMASK 3.1.0', DeprecationWarning,2)
header = [f'{len(self.comments)+4} header'] + self.comments \
+ ['grid a {} b {} c {}'.format(*self.cells),
'size x {} y {} z {}'.format(*self.size),
@ -764,26 +760,21 @@ class Grid:
"""
if fill is None: fill = np.nanmax(self.material) + 1
dtype = float if np.isnan(fill) or int(fill) != fill or self.material.dtype==np.float else int
Eulers = R.as_Euler_angles(degrees=True)
material_in = self.material.copy()
dtype = float if isinstance(fill,float) or self.material.dtype in np.sctypes['float'] else int
material = self.material
# These rotations are always applied in the reference coordinate system, i.e. (z,x,z) not (z,x',z'')
# see https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf
for angle,axes in zip(Eulers[::-1], [(0,1),(1,2),(0,1)]):
material_out = ndimage.rotate(material_in,angle,axes,order=0,
prefilter=False,output=dtype,cval=fill)
if np.prod(material_in.shape) == np.prod(material_out.shape):
# avoid scipy interpolation errors for rotations close to multiples of 90°
material_in = np.rot90(material_in,k=np.rint(angle/90.).astype(int),axes=axes)
else:
material_in = material_out
for angle,axes in zip(R.as_Euler_angles(degrees=True)[::-1], [(0,1),(1,2),(0,1)]):
material_temp = ndimage.rotate(material,angle,axes,order=0,prefilter=False,output=dtype,cval=fill)
# avoid scipy interpolation errors for rotations close to multiples of 90°
material = material_temp if np.prod(material_temp.shape) != np.prod(material.shape) else \
np.rot90(material,k=np.rint(angle/90.).astype(int),axes=axes)
origin = self.origin-(np.asarray(material_in.shape)-self.cells)*.5 * self.size/self.cells
origin = self.origin-(np.asarray(material.shape)-self.cells)*.5 * self.size/self.cells
return Grid(material = material_in,
size = self.size/self.cells*np.asarray(material_in.shape),
return Grid(material = material,
size = self.size/self.cells*np.asarray(material.shape),
origin = origin,
comments = self.comments+[util.execution_stamp('Grid','rotate')],
)

View File

@ -1,3 +1,5 @@
import inspect
import numpy as np
from . import Rotation
@ -7,7 +9,7 @@ from . import tensor
_parameter_doc = \
"""lattice : str
Either a crystal family out of [triclinic, monoclinic, orthorhombic, tetragonal, hexagonal, cubic]
or a Bravais lattice out of [aP, mP, mS, oP, oS, oI, oF, tP, tI, hP, cP, cI, cF].
or a Bravais lattice out of [aP, mP, mS, oP, oS, oI, oF, tP, tI, hP, cP, cI, cF].
When specifying a Bravais lattice, additional lattice parameters might be required:
a : float, optional
Length of lattice parameter "a".
@ -107,8 +109,7 @@ class Orientation(Rotation):
lattice = None,
a = None,b = None,c = None,
alpha = None,beta = None,gamma = None,
degrees = False,
**kwargs):
degrees = False):
"""
Initialize orientation object.
@ -199,7 +200,7 @@ class Orientation(Rotation):
def __copy__(self,**kwargs):
"""Copy."""
"""Create deep copy."""
return self.__class__(rotation=kwargs['rotation'] if 'rotation' in kwargs else self.quaternion,
lattice =kwargs['lattice'] if 'lattice' in kwargs else self.lattice
if self.lattice is not None else self.family,
@ -225,96 +226,150 @@ class Orientation(Rotation):
Orientation to check for equality.
"""
return super().__eq__(other) \
and hasattr(other, 'family') and self.family == other.family \
and hasattr(other, 'lattice') and self.lattice == other.lattice \
and hasattr(other, 'parameters') and self.parameters == other.parameters
matching_type = all([hasattr(other,attr) and getattr(self,attr) == getattr(other,attr)
for attr in ['family','lattice','parameters']])
return np.logical_and(super().__eq__(other),matching_type)
def __matmul__(self,other):
def __ne__(self,other):
"""
Rotation of vector, second or fourth order tensor, or rotation object.
Not equal to other.
Parameters
----------
other : numpy.ndarray, Rotation, or Orientation
Vector, second or fourth order tensor, or rotation object that is rotated.
other : Orientation
Orientation to check for equality.
"""
return np.logical_not(self==other)
def __mul__(self,other):
"""
Compose this orientation with other.
Parameters
----------
other : Rotation or Orientation
Object for composition.
Returns
-------
other_rot : numpy.ndarray or Rotation
Rotated vector, second or fourth order tensor, or rotation object.
composition : Orientation
Compound rotation self*other, i.e. first other then self rotation.
"""
return self.copy(rotation=Rotation.__matmul__(self,Rotation(other.quaternion))) \
if isinstance(other,self.__class__) else \
Rotation.__matmul__(self,other)
if isinstance(other,Orientation) or isinstance(other,Rotation):
return self.copy(rotation=Rotation.__mul__(self,Rotation(other.quaternion)))
else:
raise TypeError('Use "O@b", i.e. matmul, to apply Orientation "O" to object "b"')
@staticmethod
def _split_kwargs(kwargs,target):
"""
Separate keyword arguments in 'kwargs' targeted at 'target' from general keyword arguments of Orientation objects.
Parameters
----------
kwargs : dictionary
Contains all **kwargs.
target: method
Function to scan for kwarg signature.
Returns
-------
rot_kwargs: dictionary
Valid keyword arguments of 'target' function of Rotation class.
ori_kwargs: dictionary
Valid keyword arguments of Orientation object.
"""
kws = ()
for t in (target,Orientation.__init__):
kws += ({key: kwargs[key] for key in set(inspect.signature(t).parameters) & set(kwargs)},)
invalid_keys = set(kwargs)-(set(kws[0])|set(kws[1]))
if invalid_keys:
raise TypeError(f"{inspect.stack()[1][3]}() got an unexpected keyword argument '{invalid_keys.pop()}'")
return kws
@classmethod
@util.extended_docstring(Rotation.from_random,_parameter_doc)
def from_random(cls,**kwargs):
return cls(rotation=Rotation.from_random(**kwargs),**kwargs)
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_random)
return cls(rotation=Rotation.from_random(**kwargs_rot),**kwargs_ori)
@classmethod
@util.extended_docstring(Rotation.from_quaternion,_parameter_doc)
def from_quaternion(cls,**kwargs):
return cls(rotation=Rotation.from_quaternion(**kwargs),**kwargs)
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_quaternion)
return cls(rotation=Rotation.from_quaternion(**kwargs_rot),**kwargs_ori)
@classmethod
@util.extended_docstring(Rotation.from_Euler_angles,_parameter_doc)
def from_Euler_angles(cls,**kwargs):
return cls(rotation=Rotation.from_Euler_angles(**kwargs),**kwargs)
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Euler_angles)
return cls(rotation=Rotation.from_Euler_angles(**kwargs_rot),**kwargs_ori)
@classmethod
@util.extended_docstring(Rotation.from_axis_angle,_parameter_doc)
def from_axis_angle(cls,**kwargs):
return cls(rotation=Rotation.from_axis_angle(**kwargs),**kwargs)
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_axis_angle)
return cls(rotation=Rotation.from_axis_angle(**kwargs_rot),**kwargs_ori)
@classmethod
@util.extended_docstring(Rotation.from_basis,_parameter_doc)
def from_basis(cls,**kwargs):
return cls(rotation=Rotation.from_basis(**kwargs),**kwargs)
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_basis)
return cls(rotation=Rotation.from_basis(**kwargs_rot),**kwargs_ori)
@classmethod
@util.extended_docstring(Rotation.from_matrix,_parameter_doc)
def from_matrix(cls,**kwargs):
return cls(rotation=Rotation.from_matrix(**kwargs),**kwargs)
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_matrix)
return cls(rotation=Rotation.from_matrix(**kwargs_rot),**kwargs_ori)
@classmethod
@util.extended_docstring(Rotation.from_Rodrigues_vector,_parameter_doc)
def from_Rodrigues_vector(cls,**kwargs):
return cls(rotation=Rotation.from_Rodrigues_vector(**kwargs),**kwargs)
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_Rodrigues_vector)
return cls(rotation=Rotation.from_Rodrigues_vector(**kwargs_rot),**kwargs_ori)
@classmethod
@util.extended_docstring(Rotation.from_homochoric,_parameter_doc)
def from_homochoric(cls,**kwargs):
return cls(rotation=Rotation.from_homochoric(**kwargs),**kwargs)
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_homochoric)
return cls(rotation=Rotation.from_homochoric(**kwargs_rot),**kwargs_ori)
@classmethod
@util.extended_docstring(Rotation.from_cubochoric,_parameter_doc)
def from_cubochoric(cls,**kwargs):
return cls(rotation=Rotation.from_cubochoric(**kwargs),**kwargs)
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_cubochoric)
return cls(rotation=Rotation.from_cubochoric(**kwargs_rot),**kwargs_ori)
@classmethod
@util.extended_docstring(Rotation.from_spherical_component,_parameter_doc)
def from_spherical_component(cls,**kwargs):
return cls(rotation=Rotation.from_spherical_component(**kwargs),**kwargs)
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_spherical_component)
return cls(rotation=Rotation.from_spherical_component(**kwargs_rot),**kwargs_ori)
@classmethod
@util.extended_docstring(Rotation.from_fiber_component,_parameter_doc)
def from_fiber_component(cls,**kwargs):
return cls(rotation=Rotation.from_fiber_component(**kwargs),**kwargs)
kwargs_rot,kwargs_ori = Orientation._split_kwargs(kwargs,Rotation.from_fiber_component)
return cls(rotation=Rotation.from_fiber_component(**kwargs_rot),**kwargs_ori)
@classmethod
@ -429,7 +484,7 @@ class Orientation(Rotation):
raise ValueError('Missing crystal symmetry')
o = self.symmetry_operations.broadcast_to(self.symmetry_operations.shape+self.shape,mode='right')
return self.copy(rotation=o@Rotation(self.quaternion).broadcast_to(o.shape,mode='left'))
return self.copy(rotation=o*Rotation(self.quaternion).broadcast_to(o.shape,mode='left'))
@property
@ -469,26 +524,26 @@ class Orientation(Rotation):
if self.family is None:
raise ValueError('Missing crystal symmetry')
rho_abs = np.abs(self.as_Rodrigues_vector(compact=True))
rho_abs = np.abs(self.as_Rodrigues_vector(compact=True))*(1.-1.e-9)
with np.errstate(invalid='ignore'):
# using '*'/prod for 'and'
if self.family == 'cubic':
return (np.prod(np.sqrt(2)-1. >= rho_abs,axis=-1) *
(1. >= np.sum(rho_abs,axis=-1))).astype(np.bool)
(1. >= np.sum(rho_abs,axis=-1))).astype(bool)
elif self.family == 'hexagonal':
return (np.prod(1. >= rho_abs,axis=-1) *
(2. >= np.sqrt(3)*rho_abs[...,0] + rho_abs[...,1]) *
(2. >= np.sqrt(3)*rho_abs[...,1] + rho_abs[...,0]) *
(2. >= np.sqrt(3) + rho_abs[...,2])).astype(np.bool)
(2. >= np.sqrt(3) + rho_abs[...,2])).astype(bool)
elif self.family == 'tetragonal':
return (np.prod(1. >= rho_abs[...,:2],axis=-1) *
(np.sqrt(2) >= rho_abs[...,0] + rho_abs[...,1]) *
(np.sqrt(2) >= rho_abs[...,2] + 1.)).astype(np.bool)
(np.sqrt(2) >= rho_abs[...,2] + 1.)).astype(bool)
elif self.family == 'orthorhombic':
return (np.prod(1. >= rho_abs,axis=-1)).astype(np.bool)
return (np.prod(1. >= rho_abs,axis=-1)).astype(bool)
elif self.family == 'monoclinic':
return (1. >= rho_abs[...,1]).astype(np.bool)
return (1. >= rho_abs[...,1]).astype(bool)
else:
return np.all(np.isfinite(rho_abs),axis=-1)
@ -512,28 +567,28 @@ class Orientation(Rotation):
if self.family is None:
raise ValueError('Missing crystal symmetry')
rho = self.as_Rodrigues_vector(compact=True)
rho = self.as_Rodrigues_vector(compact=True)*(1.0-1.0e-9)
with np.errstate(invalid='ignore'):
if self.family == 'cubic':
return ((rho[...,0] >= rho[...,1]) &
(rho[...,1] >= rho[...,2]) &
(rho[...,2] >= 0)).astype(np.bool)
(rho[...,2] >= 0)).astype(bool)
elif self.family == 'hexagonal':
return ((rho[...,0] >= rho[...,1]*np.sqrt(3)) &
(rho[...,1] >= 0) &
(rho[...,2] >= 0)).astype(np.bool)
(rho[...,2] >= 0)).astype(bool)
elif self.family == 'tetragonal':
return ((rho[...,0] >= rho[...,1]) &
(rho[...,1] >= 0) &
(rho[...,2] >= 0)).astype(np.bool)
(rho[...,2] >= 0)).astype(bool)
elif self.family == 'orthorhombic':
return ((rho[...,0] >= 0) &
(rho[...,1] >= 0) &
(rho[...,2] >= 0)).astype(np.bool)
(rho[...,2] >= 0)).astype(bool)
elif self.family == 'monoclinic':
return ((rho[...,1] >= 0) &
(rho[...,2] >= 0)).astype(np.bool)
(rho[...,2] >= 0)).astype(bool)
else:
return np.ones_like(rho[...,0],dtype=bool)
@ -608,7 +663,7 @@ class Orientation(Rotation):
o,lattice = self.relation_operations(model,return_lattice=True)
target = Orientation(lattice=lattice)
o = o.broadcast_to(o.shape+self.shape,mode='right')
return self.copy(rotation=o@Rotation(self.quaternion).broadcast_to(o.shape,mode='left'),
return self.copy(rotation=o*Rotation(self.quaternion).broadcast_to(o.shape,mode='left'),
lattice=lattice,
b = self.b if target.ratio['b'] is None else self.a*target.ratio['b'],
c = self.c if target.ratio['c'] is None else self.a*target.ratio['c'],

View File

@ -80,12 +80,12 @@ class Result:
self.out_type_ho += f['/'.join([self.increments[0],'homogenization',m])].keys()
self.out_type_ho = list(set(self.out_type_ho)) # make unique
self.selection = {'increments': self.increments,
'phases': self.phases,
'homogenizations': self.homogenizations,
'out_type_ph': self.out_type_ph,
'out_type_ho': self.out_type_ho
}
self.visible = {'increments': self.increments,
'phases': self.phases,
'homogenizations': self.homogenizations,
'out_type_ph': self.out_type_ph,
'out_type_ho': self.out_type_ho
}
self.fname = Path(fname).absolute()
@ -94,23 +94,23 @@ class Result:
def __repr__(self):
"""Show summary of file content."""
all_selected_increments = self.selection['increments']
visible_increments = self.visible['increments']
self.pick('increments',all_selected_increments[0:1])
self.view('increments',visible_increments[0:1])
first = self.list_data()
self.pick('increments',all_selected_increments[-1:])
last = '' if len(all_selected_increments) < 2 else self.list_data()
self.view('increments',visible_increments[-1:])
last = '' if len(visible_increments) < 2 else self.list_data()
self.pick('increments',all_selected_increments)
self.view('increments',visible_increments)
in_between = '' if len(all_selected_increments) < 3 else \
''.join([f'\n{inc}\n ...\n' for inc in all_selected_increments[1:-2]])
in_between = '' if len(visible_increments) < 3 else \
''.join([f'\n{inc}\n ...\n' for inc in visible_increments[1:-1]])
return util.srepr(first + in_between + last)
def _manage_selection(self,action,what,datasets):
def _manage_view(self,action,what,datasets):
"""
Manages the visibility of the groups.
@ -119,10 +119,10 @@ class Result:
action : str
Select from 'set', 'add', and 'del'.
what : str
Attribute to change (must be from self.selection).
Attribute to change (must be from self.visible).
datasets : list of str or bool
Name of datasets as list, supports ? and * wildcards.
True is equivalent to [*], False is equivalent to []
Name of datasets as list; supports ? and * wildcards.
True is equivalent to [*], False is equivalent to [].
"""
def natural_sort(key):
@ -156,18 +156,18 @@ class Result:
choice.append(self.increments[idx+1])
valid = [e for e_ in [glob.fnmatch.filter(getattr(self,what),s) for s in choice] for e in e_]
existing = set(self.selection[what])
existing = set(self.visible[what])
if action == 'set':
self.selection[what] = valid
self.visible[what] = valid
elif action == 'add':
add = existing.union(valid)
add_sorted = sorted(add, key=natural_sort)
self.selection[what] = add_sorted
self.visible[what] = add_sorted
elif action == 'del':
diff = existing.difference(valid)
diff_sorted = sorted(diff, key=natural_sort)
self.selection[what] = diff_sorted
self.visible[what] = diff_sorted
def _get_attribute(self,path,attr):
@ -200,7 +200,7 @@ class Result:
self._allow_modification = True
def disallow_modification(self):
"""Disllow to overwrite existing data (default case)."""
"""Disallow to overwrite existing data (default case)."""
self._allow_modification = False
@ -245,84 +245,84 @@ class Result:
def iterate(self,what):
"""
Iterate over selection items by setting each one selected.
Iterate over visible items and view them independently.
Parameters
----------
what : str
Attribute to change (must be from self.selection).
Attribute to change (must be from self.visible).
"""
datasets = self.selection[what]
last_selection = datasets.copy()
datasets = self.visible[what]
last_view = datasets.copy()
for dataset in datasets:
if last_selection != self.selection[what]:
self._manage_selection('set',what,datasets)
if last_view != self.visible[what]:
self._manage_view('set',what,datasets)
raise Exception
self._manage_selection('set',what,dataset)
last_selection = self.selection[what]
self._manage_view('set',what,dataset)
last_view = self.visible[what]
yield dataset
self._manage_selection('set',what,datasets)
self._manage_view('set',what,datasets)
def pick(self,what,datasets):
def view(self,what,datasets):
"""
Set selection.
Set view.
Parameters
----------
what : str
attribute to change (must be from self.selection)
Attribute to change (must be from self.visible).
datasets : list of str or bool
name of datasets as list, supports ? and * wildcards.
True is equivalent to [*], False is equivalent to []
Name of datasets as list; supports ? and * wildcards.
True is equivalent to [*], False is equivalent to [].
"""
self._manage_selection('set',what,datasets)
self._manage_view('set',what,datasets)
def pick_more(self,what,datasets):
def view_more(self,what,datasets):
"""
Add to selection.
Add to view.
Parameters
----------
what : str
attribute to change (must be from self.selection)
Attribute to change (must be from self.visible).
datasets : list of str or bool
name of datasets as list, supports ? and * wildcards.
True is equivalent to [*], False is equivalent to []
Name of datasets as list; supports ? and * wildcards.
True is equivalent to [*], False is equivalent to [].
"""
self._manage_selection('add',what,datasets)
self._manage_view('add',what,datasets)
def pick_less(self,what,datasets):
def view_less(self,what,datasets):
"""
Delete from selection.
Delete from view.
Parameters
----------
what : str
attribute to change (must be from self.selection)
Attribute to change (must be from self.visible).
datasets : list of str or bool
name of datasets as list, supports ? and * wildcards.
True is equivalent to [*], False is equivalent to []
Name of datasets as list; supports ? and * wildcards.
True is equivalent to [*], False is equivalent to [].
"""
self._manage_selection('del',what,datasets)
self._manage_view('del',what,datasets)
def rename(self,name_old,name_new):
"""
Rename datasets.
Rename dataset.
Parameters
----------
name_old : str
name of the datasets to be renamed
Name of the dataset to be renamed.
name_new : str
new name of the datasets
New name of the dataset.
"""
if self._allow_modification:
@ -353,13 +353,13 @@ class Result:
----------
datasets : iterable or str
constituent : int
Constituent to consider for phase data
Constituent to consider for phase data.
tagged : bool
tag Table.column name with '#constituent'
defaults to False
Tag Table.column name with '#constituent'.
Defaults to False.
split : bool
split Table by increment and return dictionary of Tables
defaults to True
Split Table by increment and return dictionary of Tables.
Defaults to True.
"""
sets = datasets if hasattr(datasets,'__iter__') and not isinstance(datasets,str) else \
@ -371,7 +371,7 @@ class Result:
with h5py.File(self.fname,'r') as f:
for dataset in sets:
for group in self.groups_with_datasets(dataset):
path = os.path.join(group,dataset)
path = '/'.join([group,dataset])
inc,prop,name,cat,item = (path.split('/') + ['']*5)[:5]
key = '/'.join([prop,name+tag])
if key not in inGeom:
@ -388,15 +388,15 @@ class Result:
np.nan,
dtype=np.dtype(f[path]))
data[inGeom[key]] = (f[path] if len(shape)>1 else np.expand_dims(f[path],1))[inData[key]]
path = (os.path.join(*([prop,name]+([cat] if cat else [])+([item] if item else []))) if split else path)+tag
path = ('/'.join([prop,name]+([cat] if cat else [])+([item] if item else [])) if split else path)+tag
if split:
try:
tbl[inc].add(path,data)
tbl[inc] = tbl[inc].add(path,data)
except KeyError:
tbl[inc] = Table(data.reshape(self.N_materialpoints,-1),{path:data.shape[1:]})
else:
try:
tbl.add(path,data)
tbl = tbl.add(path,data)
except AttributeError:
tbl = Table(data.reshape(self.N_materialpoints,-1),{path:data.shape[1:]})
@ -415,7 +415,7 @@ class Result:
are considered as they contain user-relevant data.
Single strings will be treated as list with one entry.
Wild card matching is allowed, but the number of arguments need to fit.
Wild card matching is allowed, but the number of arguments needs to fit.
Parameters
----------
@ -1134,8 +1134,7 @@ class Result:
"""
chunk_size = 1024**2//8
num_threads = damask.environment.options['DAMASK_NUM_THREADS']
pool = mp.Pool(int(num_threads) if num_threads is not None else None)
pool = mp.Pool(int(os.environ.get('OMP_NUM_THREADS',1)))
lock = mp.Manager().Lock()
groups = self.groups_with_datasets(datasets.values())
@ -1190,8 +1189,8 @@ class Result:
"""
Write XDMF file to directly visualize data in DADF5 file.
This works only for scalar, 3-vector and 3x3-tensor data.
Selection is not taken into account.
The view is not taken into account, i.e. the content of the
whole file will be included.
"""
if self.N_constituents != 1 or len(self.phases) != 1 or not self.structured:
raise TypeError('XDMF output requires homogeneous grid')
@ -1288,7 +1287,7 @@ class Result:
np.prod(shape))}
data_items[-1].text=f'{os.path.split(self.fname)[1]}:{name}'
with open(self.fname.with_suffix('.xdmf').name,'w') as f:
with open(self.fname.with_suffix('.xdmf').name,'w',newline='\n') as f:
f.write(xml.dom.minidom.parseString(ET.tostring(xdmf).decode()).toprettyxml())
@ -1320,10 +1319,10 @@ class Result:
N_digits = int(np.floor(np.log10(max(1,int(self.increments[-1][3:])))))+1
for inc in util.show_progress(self.iterate('increments'),len(self.selection['increments'])):
for inc in util.show_progress(self.iterate('increments'),len(self.visible['increments'])):
picked_backup_ho = self.selection['homogenizations'].copy()
self.pick('homogenizations',False)
viewed_backup_ho = self.visible['homogenizations'].copy()
self.view('homogenizations',False)
for label in (labels if isinstance(labels,list) else [labels]):
for o in self.iterate('out_type_ph'):
for c in range(self.N_constituents):
@ -1343,10 +1342,10 @@ class Result:
ph_name = re.compile(r'(?<=(phase\/))(.*?)(?=(mechanics))') # identify phase name
dset_name = prefix+re.sub(ph_name,r'',paths[0].split('/',1)[1]) # remove phase name
v.add(array,dset_name+f' / {self._get_attribute(paths[0],"Unit")}')
self.pick('homogenizations',picked_backup_ho)
self.view('homogenizations',viewed_backup_ho)
picked_backup_ph = self.selection['phases'].copy()
self.pick('phases',False)
viewed_backup_ph = self.visible['phases'].copy()
self.view('phases',False)
for label in (labels if isinstance(labels,list) else [labels]):
for _ in self.iterate('out_type_ho'):
paths = self.get_dataset_location(label)
@ -1354,7 +1353,7 @@ class Result:
continue
array = self.read_dataset(paths)
v.add(array,paths[0].split('/',1)[1]+f' / {self._get_attribute(paths[0],"Unit")}')
self.pick('phases',picked_backup_ph)
self.view('phases',viewed_backup_ph)
u = self.read_dataset(self.get_dataset_location('u_n' if mode.lower() == 'cell' else 'u_p'))
v.add(u,'u')

View File

@ -35,6 +35,11 @@ class Rotation:
- b = Q @ a
- b = np.dot(Q.as_matrix(),a)
Compound rotations R1 (first) and R2 (second):
- R = R2 * R1
- R = Rotation.from_matrix(np.dot(R2.as_matrix(),R1.as_matrix())
References
----------
D. Rowenhorst et al., Modelling and Simulation in Materials Science and Engineering 23:083501, 2015
@ -65,22 +70,13 @@ class Rotation:
def __repr__(self):
"""Represent rotation as unit quaternion, rotation matrix, and Bunge-Euler angles."""
if self == Rotation():
return 'Rotation()'
else:
return f'Quaternions {self.shape}:\n'+str(self.quaternion) \
if self.quaternion.shape != (4,) else \
'\n'.join([
'Quaternion: (real={:.3f}, imag=<{:+.3f}, {:+.3f}, {:+.3f}>)'.format(*(self.quaternion)),
'Matrix:\n{}'.format(np.round(self.as_matrix(),8)),
'Bunge Eulers / deg: ({:3.2f}, {:3.2f}, {:3.2f})'.format(*self.as_Euler_angles(degrees=True)),
])
"""Represent rotation as unit quaternion(s)."""
return f'Quaternion{" " if self.quaternion.shape == (4,) else "s of shape "+str(self.quaternion.shape)+chr(10)}'\
+ str(self.quaternion)
# ToDo: Check difference __copy__ vs __deepcopy__
def __copy__(self,**kwargs):
"""Copy."""
"""Create deep copy."""
return self.__class__(rotation=kwargs['rotation'] if 'rotation' in kwargs else self.quaternion)
copy = __copy__
@ -97,6 +93,26 @@ class Rotation:
"""
Equal to other.
Equality is determined taking limited floating point precision into account.
See numpy.allclose for details.
Parameters
----------
other : Rotation
Rotation to check for equality.
"""
s = self.quaternion
o = other.quaternion
if self.shape == () == other.shape:
return np.allclose(s,o) or (np.isclose(s[0],0.0) and np.allclose(s,-1.0*o))
else:
return np.all(np.isclose(s,o),-1) + np.all(np.isclose(s,-1.0*o),-1) * np.isclose(s[...,0],0.0)
def __ne__(self,other):
"""
Not equal to other.
Equality is determined taking limited floating point precision into
account. See numpy.allclose for details.
@ -106,13 +122,21 @@ class Rotation:
Rotation to check for equality.
"""
return np.prod(self.shape,dtype=int) == np.prod(other.shape,dtype=int) \
and np.allclose(self.quaternion,other.quaternion)
return np.logical_not(self==other)
def __array__(self):
"""Initializer for numpy."""
return self.quaternion
@property
def size(self):
return self.quaternion[...,0].size
@property
def shape(self):
return self.quaternion.shape[:-1]
return self.quaternion[...,0].shape
def __len__(self):
@ -127,41 +151,46 @@ class Rotation:
return dup
def __pow__(self,pwr):
def __pow__(self,exp):
"""
Raise quaternion to power.
Equivalent to performing the rotation 'pwr' times.
Perform the rotation 'exp' times.
Parameters
----------
pwr : float
Power to raise quaternion to.
exp : float
Exponent.
"""
phi = np.arccos(self.quaternion[...,0:1])
p = self.quaternion[...,1:]/np.linalg.norm(self.quaternion[...,1:],axis=-1,keepdims=True)
return self.copy(rotation=Rotation(np.block([np.cos(pwr*phi),np.sin(pwr*phi)*p]))._standardize())
return self.copy(rotation=Rotation(np.block([np.cos(exp*phi),np.sin(exp*phi)*p]))._standardize())
def __mul__(self,other):
"""Standard multiplication is not implemented."""
raise NotImplementedError('Use "R@b", i.e. matmul, to apply rotation "R" to object "b"')
def __matmul__(self,other):
def __ipow__(self,exp):
"""
Rotation of vector, second or fourth order tensor, or rotation object.
Perform the rotation 'exp' times (in-place).
Parameters
----------
other : numpy.ndarray or Rotation
Vector, second or fourth order tensor, or rotation object that is rotated.
exp : float
Exponent.
"""
return self**exp
def __mul__(self,other):
"""
Compose this rotation with other.
Parameters
----------
other : Rotation of shape(self.shape)
Rotation for composition.
Returns
-------
other_rot : numpy.ndarray or Rotation
Rotated vector, second or fourth order tensor, or rotation object.
composition : Rotation
Compound rotation self*other, i.e. first other then self rotation.
"""
if isinstance(other,Rotation):
@ -172,8 +201,71 @@ class Rotation:
q = (q_m*q_o - np.einsum('...i,...i',p_m,p_o).reshape(self.shape+(1,)))
p = q_m*p_o + q_o*p_m + _P * np.cross(p_m,p_o)
return Rotation(np.block([q,p]))._standardize()
else:
raise TypeError('Use "R@b", i.e. matmul, to apply rotation "R" to object "b"')
elif isinstance(other,np.ndarray):
def __imul__(self,other):
"""
Compose this rotation with other (in-place).
Parameters
----------
other : Rotation of shape(self.shape)
Rotation for composition.
"""
return self*other
def __truediv__(self,other):
"""
Compose this rotation with inverse of other.
Parameters
----------
other : damask.Rotation of shape (self.shape)
Rotation to inverse composition.
Returns
-------
composition : Rotation
Compound rotation self*(~other), i.e. first inverse of other then self rotation.
"""
if isinstance(other,Rotation):
return self*~other
else:
raise TypeError('Use "R@b", i.e. matmul, to apply rotation "R" to object "b"')
def __itruediv__(self,other):
"""
Compose this rotation with inverse of other (in-place).
Parameters
----------
other : Rotation of shape (self.shape)
Rotation to inverse composition.
"""
return self/other
def __matmul__(self,other):
"""
Rotation of vector, second order tensor, or fourth order tensor.
Parameters
----------
other : numpy.ndarray of shape (...,3), (...,3,3), or (...,3,3,3,3)
Vector or tensor on which to apply the rotation.
Returns
-------
rotated : numpy.ndarray of shape (...,3), (...,3,3), or (...,3,3,3,3)
Rotated vector or tensor, i.e. transformed to frame defined by rotation.
"""
if isinstance(other,np.ndarray):
if self.shape + (3,) == other.shape:
q_m = self.quaternion[...,0]
p_m = self.quaternion[...,1:]
@ -193,9 +285,13 @@ class Rotation:
return np.einsum('...im,...jn,...ko,...lp,...mnop',R,R,R,R,other)
else:
raise ValueError('Can only rotate vectors, 2nd order tensors, and 4th order tensors')
elif isinstance(other,Rotation):
raise TypeError('Use "R1*R2", i.e. multiplication, to compose rotations "R1" and "R2"')
else:
raise TypeError(f'Cannot rotate {type(other)}')
apply = __matmul__
def _standardize(self):
"""Standardize quaternion (ensure positive real hemisphere)."""
@ -296,7 +392,7 @@ class Rotation:
Rotation to which the misorientation is computed.
"""
return other@~self
return other*~self
################################################################################################
@ -379,15 +475,17 @@ class Rotation:
Parameters
----------
vector : bool, optional
Return as actual Rodrigues-Frank vector, i.e. axis
and angle argument are not separated.
compact : bool, optional
Return as actual Rodrigues-Frank vector,
i.e. axis and angle argument are not separated.
Returns
-------
rho : numpy.ndarray of shape (...,4) unless vector == True:
numpy.ndarray of shape (...,3)
Rodrigues-Frank vector: [n_1, n_2, n_3, tan(ω/2)], ǀnǀ = 1 and ω [0,π].
rho : numpy.ndarray of shape (...,4) containing
[n_1, n_2, n_3, tan(ω/2)], ǀnǀ = 1 and ω [0,π]
unless compact == True:
numpy.ndarray of shape (...,3) containing
tan(ω/2) [n_1, n_2, n_3], ω [0,π].
"""
ro = Rotation._qu2ro(self.quaternion)
@ -415,8 +513,8 @@ class Rotation:
Returns
-------
c : numpy.ndarray of shape (...,3)
Cubochoric vector: (c_1, c_2, c_3), max(c_i) < 1/2*π^(2/3).
x : numpy.ndarray of shape (...,3)
Cubochoric vector: (x_1, x_2, x_3), max(x_i) < 1/2*π^(2/3).
"""
return Rotation._qu2cu(self.quaternion)
@ -427,8 +525,7 @@ class Rotation:
@staticmethod
def from_quaternion(q,
accept_homomorph = False,
P = -1,
**kwargs):
P = -1):
"""
Initialize from quaternion.
@ -463,8 +560,7 @@ class Rotation:
@staticmethod
def from_Euler_angles(phi,
degrees = False,
**kwargs):
degrees = False):
"""
Initialize from Bunge-Euler angles.
@ -491,8 +587,7 @@ class Rotation:
def from_axis_angle(axis_angle,
degrees = False,
normalize = False,
P = -1,
**kwargs):
P = -1):
"""
Initialize from Axis angle pair.
@ -529,8 +624,7 @@ class Rotation:
@staticmethod
def from_basis(basis,
orthonormal = True,
reciprocal = False,
**kwargs):
reciprocal = False):
"""
Initialize from lattice basis vectors.
@ -564,7 +658,7 @@ class Rotation:
return Rotation(Rotation._om2qu(om))
@staticmethod
def from_matrix(R,**kwargs):
def from_matrix(R):
"""
Initialize from rotation matrix.
@ -608,8 +702,7 @@ class Rotation:
@staticmethod
def from_Rodrigues_vector(rho,
normalize = False,
P = -1,
**kwargs):
P = -1):
"""
Initialize from Rodrigues-Frank vector (angle separated from axis).
@ -640,8 +733,7 @@ class Rotation:
@staticmethod
def from_homochoric(h,
P = -1,
**kwargs):
P = -1):
"""
Initialize from homochoric vector.
@ -667,21 +759,20 @@ class Rotation:
return Rotation(Rotation._ho2qu(ho))
@staticmethod
def from_cubochoric(c,
P = -1,
**kwargs):
def from_cubochoric(x,
P = -1):
"""
Initialize from cubochoric vector.
Parameters
----------
c : numpy.ndarray of shape (...,3)
Cubochoric vector: (c_1, c_2, c_3), max(c_i) < 1/2*π^(2/3).
x : numpy.ndarray of shape (...,3)
Cubochoric vector: (x_1, x_2, x_3), max(x_i) < 1/2*π^(2/3).
P : int {-1,1}, optional
Convention used. Defaults to -1.
"""
cu = np.array(c,dtype=float)
cu = np.array(x,dtype=float)
if cu.shape[:-2:-1] != (3,):
raise ValueError('Invalid shape.')
if abs(P) != 1:
@ -697,8 +788,7 @@ class Rotation:
@staticmethod
def from_random(shape = None,
rng_seed = None,
**kwargs):
rng_seed = None):
"""
Draw random rotation.
@ -791,8 +881,7 @@ class Rotation:
sigma,
N = 500,
degrees = True,
rng_seed = None,
**kwargs):
rng_seed = None):
"""
Calculate set of rotations with Gaussian distribution around center.
@ -819,7 +908,7 @@ class Rotation:
np.sqrt(1-u**2)*np.sin(Theta),
u, omega])
return Rotation.from_axis_angle(p) @ center
return Rotation.from_axis_angle(p) * center
@staticmethod
@ -828,8 +917,7 @@ class Rotation:
sigma = 0.0,
N = 500,
degrees = True,
rng_seed = None,
**kwargs):
rng_seed = None):
"""
Calculate set of rotations with Gaussian distribution around direction.
@ -870,8 +958,8 @@ class Rotation:
f[::2,:3] *= -1 # flip half the rotation axes to negative sense
return R_align.broadcast_to(N) \
@ Rotation.from_axis_angle(p,normalize=True) \
@ Rotation.from_axis_angle(f)
* Rotation.from_axis_angle(p,normalize=True) \
* Rotation.from_axis_angle(f)
####################################################################################################
@ -1060,7 +1148,6 @@ class Rotation:
@staticmethod
def _om2ax(om):
"""Rotation matrix to axis angle pair."""
#return Rotation._qu2ax(Rotation._om2qu(om)) # HOTFIX
diag_delta = -_P*np.block([om[...,1,2:3]-om[...,2,1:2],
om[...,2,0:1]-om[...,0,2:3],
om[...,0,1:2]-om[...,1,0:1]

View File

@ -26,7 +26,7 @@ class Table:
comments_ = [comments] if isinstance(comments,str) else comments
self.comments = [] if comments_ is None else [c for c in comments_]
self.data = pd.DataFrame(data=data)
self.shapes = { k:(v,) if isinstance(v,(np.int,int)) else v for k,v in shapes.items() }
self.shapes = { k:(v,) if isinstance(v,(np.int64,np.int32,int)) else v for k,v in shapes.items() }
self._label_uniform()
def __repr__(self):
@ -42,12 +42,10 @@ class Table:
return len(self.data)
def __copy__(self):
"""Copy Table."""
"""Create deep copy."""
return copy.deepcopy(self)
def copy(self):
"""Copy Table."""
return self.__copy__()
copy = __copy__
def _label_discrete(self):
@ -191,6 +189,11 @@ class Table:
label : str
Column label.
Returns
-------
data : numpy.ndarray
Array of column data.
"""
if re.match(r'[0-9]*?_',label):
idx,key = label.split('_',1)
@ -214,6 +217,11 @@ class Table:
info : str, optional
Human-readable information about the new data.
Returns
-------
table : Table
Updated table.
"""
dup = self.copy()
dup._add_comment(label,data.shape[1:],info)
@ -240,6 +248,11 @@ class Table:
info : str, optional
Human-readable information about the modified data.
Returns
-------
table : Table
Updated table.
"""
dup = self.copy()
dup._add_comment(label,data.shape[1:],info)
@ -263,6 +276,11 @@ class Table:
label : str
Column label.
Returns
-------
table : Table
Updated table.
"""
dup = self.copy()
dup.data.drop(columns=label,inplace=True)
@ -281,6 +299,11 @@ class Table:
label_new : str or iterable of str
New column label(s).
Returns
-------
table : Table
Updated table.
"""
dup = self.copy()
columns = dict(zip([old] if isinstance(old,str) else old,
@ -302,6 +325,11 @@ class Table:
ascending : bool or list, optional
Set sort order.
Returns
-------
table : Table
Updated table.
"""
dup = self.copy()
dup._label_discrete()
@ -322,6 +350,11 @@ class Table:
other : Table
Table to append.
Returns
-------
table : Table
Concatenated table.
"""
if self.shapes != other.shapes or not self.data.columns.equals(other.data.columns):
raise KeyError('Labels or shapes or order do not match')
@ -342,6 +375,11 @@ class Table:
other : Table
Table to join.
Returns
-------
table : Table
Joined table.
"""
if set(self.shapes) & set(other.shapes) or self.data.shape[0] != other.data.shape[0]:
raise KeyError('Dublicated keys or row count mismatch')
@ -382,7 +420,7 @@ class Table:
[f'# {comment}' for comment in self.comments]
try:
fhandle = open(fname,'w')
fhandle = open(fname,'w',newline='\n')
except TypeError:
fhandle = fname

View File

@ -5,6 +5,7 @@ import logging
import logging.config
from collections.abc import Iterable
from optparse import OptionParser
from pathlib import Path
import numpy as np
@ -180,7 +181,7 @@ class Test:
def fileInRoot(self,dir,file):
"""Path to a file in the root directory of DAMASK."""
return str(damask.environment.root_dir/dir/file)
return str(Path(os.environ['DAMASK_ROOT'])/dir/file)
def fileInReference(self,file):
@ -282,40 +283,6 @@ class Test:
return out,error
def compare_Array(self,File1,File2):
import numpy as np
logging.info('\n '.join(['comparing',File1,File2]))
table = damask.Table.load(File1)
len1 = len(table.comments)+2
table = damask.Table.load(File2)
len2 = len(table.comments)+2
refArray = np.nan_to_num(np.genfromtxt(File1,missing_values='n/a',skip_header = len1,autostrip=True))
curArray = np.nan_to_num(np.genfromtxt(File2,missing_values='n/a',skip_header = len2,autostrip=True))
if len(curArray) == len(refArray):
refArrayNonZero = refArray[refArray.nonzero()]
curArray = curArray[refArray.nonzero()]
max_err = np. max(abs(refArrayNonZero[curArray.nonzero()]/curArray[curArray.nonzero()]-1.))
max_loc = np.argmax(abs(refArrayNonZero[curArray.nonzero()]/curArray[curArray.nonzero()]-1.))
refArrayNonZero = refArrayNonZero[curArray.nonzero()]
curArray = curArray[curArray.nonzero()]
print(f' ********\n * maximum relative error {max_err} between {refArrayNonZero[max_loc]} and {curArray[max_loc]}\n ********')
return max_err
else:
raise Exception(f'mismatch in array sizes ({len(refArray)} and {len(curArray)}) to compare')
def compare_ArrayRefCur(self,ref,cur=''):
if cur == '': cur = ref
refName = self.fileInReference(ref)
curName = self.fileInCurrent(cur)
return self.compare_Array(refName,curName)
def compare_Table(self,headings0,file0,
headings1,file1,
normHeadings='',normType=None,
@ -468,101 +435,6 @@ class Test:
return (mean < meanTol) & (std < stdTol)
def compare_Tables(self,
files = [None,None], # list of file names
columns = [None], # list of list of column labels (per file)
rtol = 1e-5,
atol = 1e-8,
debug = False):
"""Compare multiple tables with np.allclose."""
if not (isinstance(files, Iterable) and not isinstance(files, str)): # check whether list of files is requested
files = [str(files)]
if len(files) < 2: return True # single table is always close to itself...
tables = [damask.Table.load(filename) for filename in files]
columns += [columns[0]]*(len(files)-len(columns)) # extend to same length as files
columns = columns[:len(files)] # truncate to same length as files
for i,column in enumerate(columns):
if column is None: columns[i] = list(tables[i].shapes.keys()) # if no column is given, use all
logging.info('comparing ASCIItables')
for i in range(len(columns)):
columns[i] = columns[0] if not columns[i] else \
([columns[i]] if not (isinstance(columns[i], Iterable) and not isinstance(columns[i], str)) else \
columns[i]
)
logging.info(files[i]+': '+','.join(columns[i]))
dimensions = [np.prod(tables[0].shapes[c]) for c in columns[0]] # width of each requested column
maximum = np.zeros_like(columns[0],dtype=float) # one magnitude per column entry
data = [] # list of feature table extracted from each file (ASCII table)
for i,(table,labels) in enumerate(zip(tables,columns)):
if np.any(dimensions != [np.prod(table.shapes[c]) for c in labels]): # check data object consistency
logging.critical(f'Table {files[i]} differs in data layout.')
return False
data.append(np.hstack(list(table.get(label) for label in labels)).astype(np.float)) # store
for j,label in enumerate(labels): # iterate over object labels
maximum[j] = np.maximum(
maximum[j],
np.amax(np.linalg.norm(table.get(label),
axis=1))
) # find maximum Euclidean norm across rows
maximum = np.where(maximum > 0.0, maximum, 1.0) # avoid div by zero for zero columns
maximum = np.repeat(maximum,dimensions) # spread maximum over columns of each object
for i in range(len(data)):
data[i] /= maximum # normalize each table
logging.info(f'shape of data {i}: {data[i].shape}')
if debug:
violators = np.absolute(data[0]-data[1]) > atol + rtol*np.absolute(data[1])
logging.info(f'shape of violators: {violators.shape}')
for j,culprits in enumerate(violators):
goodguys = np.logical_not(culprits)
if culprits.any():
logging.info(f'{j} has {np.sum(culprits)}')
logging.info(f'deviation: {np.absolute(data[0][j]-data[1][j])[culprits]}')
logging.info(f'data : {np.absolute(data[1][j])[culprits]}')
logging.info(f'deviation: {np.absolute(data[0][j]-data[1][j])[goodguys]}')
logging.info(f'data : {np.absolute(data[1][j])[goodguys]}')
allclose = True # start optimistic
for i in range(1,len(data)):
allclose &= np.allclose(data[i-1],data[i],rtol,atol) # accumulate "pessimism"
return allclose
def compare_TableRefCur(self,headingsRef,ref,headingsCur='',cur='',
normHeadings='',normType=None,
absoluteTolerance=False,perLine=False,skipLines=[]):
return self.compare_Table(headingsRef,
self.fileInReference(ref),
headingsRef if headingsCur == '' else headingsCur,
self.fileInCurrent(ref if cur == '' else cur),
normHeadings,normType,
absoluteTolerance,perLine,skipLines)
def compare_TableCurCur(self,headingsCur0,Cur0,Cur1,
headingsCur1='',
normHeadings='',normType=None,
absoluteTolerance=False,perLine=False,skipLines=[]):
return self.compare_Table(headingsCur0,
self.fileInCurrent(Cur0),
headingsCur0 if headingsCur1 == '' else headingsCur1,
self.fileInCurrent(Cur1),
normHeadings,normType,absoluteTolerance,perLine,skipLines)
def report_Success(self,culprit):
ret = culprit

View File

@ -10,7 +10,6 @@ from vtk.util.numpy_support import numpy_to_vtkIdTypeArray as np_to_vtkIdTypeArr
from vtk.util.numpy_support import vtk_to_numpy as vtk_to_np
from . import util
from . import environment
from . import Table
@ -247,8 +246,8 @@ class VTK:
raise ValueError('No label defined for numpy.ndarray')
N_data = data.shape[0]
d = np_to_vtk((data.astype(np.float32) if data.dtype in [np.float64, np.float128]
else data).reshape(N_data,-1),deep=True) # avoid large files
d = np_to_vtk((data.astype(np.single) if data.dtype in [np.double, np.longdouble] else
data).reshape(N_data,-1),deep=True) # avoid large files
d.SetName(label)
if N_data == N_points:
@ -348,6 +347,21 @@ class VTK:
See http://compilatrix.com/article/vtk-1 for further ideas.
"""
try:
import wx
_ = wx.App(False) # noqa
width, height = wx.GetDisplaySize()
except ImportError:
try:
import tkinter
tk = tkinter.Tk()
width = tk.winfo_screenwidth()
height = tk.winfo_screenheight()
tk.destroy()
except Exception as e:
width = 1024
height = 768
mapper = vtk.vtkDataSetMapper()
mapper.SetInputData(self.vtk_data)
actor = vtk.vtkActor()
@ -361,7 +375,7 @@ class VTK:
ren.AddActor(actor)
ren.SetBackground(0.2,0.2,0.2)
window.SetSize(environment.screen_size[0],environment.screen_size[1])
window.SetSize(width,height)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(window)

View File

@ -2,14 +2,13 @@ import subprocess
import shlex
import re
import io
import os
from pathlib import Path
from .. import environment
class Marc:
"""Wrapper to run DAMASK with MSCMarc."""
def __init__(self,version=environment.options['MSC_VERSION']):
def __init__(self,version=os.environ['MSC_VERSION']):
"""
Create a Marc solver object.
@ -25,9 +24,7 @@ class Marc:
@property
def library_path(self):
path_MSC = environment.options['MSC_ROOT']
path_lib = Path(f'{path_MSC}/mentat{self.version}/shlib/linux64')
path_lib = Path(f'{os.environ["MSC_ROOT"]}/mentat{self.version}/shlib/linux64')
if not path_lib.is_dir():
raise FileNotFoundError(f'library path "{path_lib}" not found')
@ -37,9 +34,7 @@ class Marc:
@property
def tools_path(self):
path_MSC = environment.options['MSC_ROOT']
path_tools = Path(f'{path_MSC}/marc{self.version}/tools')
path_tools = Path(f'{os.environ["MSC_ROOT"]}/marc{self.version}/tools')
if not path_tools.is_dir():
raise FileNotFoundError(f'tools path "{path_tools}" not found')
@ -54,7 +49,7 @@ class Marc:
optimization = '',
):
usersub = environment.root_dir/'src/DAMASK_marc'
usersub = Path(os.environ['DAMASK_ROOT'])/'src/DAMASK_marc'
usersub = usersub.parent/(usersub.name + ('.f90' if compile else '.marc'))
if not usersub.is_file():
raise FileNotFoundError(f'subroutine ({"source" if compile else "binary"}) "{usersub}" not found')
@ -71,7 +66,7 @@ class Marc:
if logfile is not None:
try:
f = open(logfile,'w+')
f = open(logfile,'w+',newline='\n')
except TypeError:
f = logfile
else:

View File

@ -133,6 +133,8 @@ def execute(cmd,
stdout = stdout.decode('utf-8').replace('\x08','')
stderr = stderr.decode('utf-8').replace('\x08','')
if process.returncode != 0:
print(stdout)
print(stderr)
raise RuntimeError(f"'{cmd}' failed with returncode {process.returncode}")
return stdout, stderr
@ -183,7 +185,7 @@ def scale_to_coprime(v):
# Python 3.9 provides math.lcm, see https://stackoverflow.com/questions/51716916.
return a * b // np.gcd(a, b)
m = (np.array(v) * reduce(lcm, map(lambda x: int(get_square_denominator(x)),v)) ** 0.5).astype(np.int)
m = (np.array(v) * reduce(lcm, map(lambda x: int(get_square_denominator(x)),v)) ** 0.5).astype(int)
m = m//reduce(np.gcd,m)
with np.errstate(invalid='ignore'):
@ -193,7 +195,7 @@ def scale_to_coprime(v):
return m
def project_stereographic(vector,normalize=False):
def project_stereographic(vector,direction='z',normalize=True,keepdims=False):
"""
Apply stereographic projection to vector.
@ -201,18 +203,37 @@ def project_stereographic(vector,normalize=False):
----------
vector : numpy.ndarray of shape (...,3)
Vector coordinates to be projected.
direction : str
Projection direction 'x', 'y', or 'z'.
Defaults to 'z'.
normalize : bool
Ensure unit length for vector. Defaults to False.
Ensure unit length of input vector. Defaults to True.
keepdims : bool
Maintain three-dimensional output coordinates.
Default two-dimensional output uses right-handed frame spanned by
the next and next-next axis relative to the projection direction,
e.g. x-y when projecting along z and z-x when projecting along y.
Returns
-------
coordinates : numpy.ndarray of shape (...,2)
coordinates : numpy.ndarray of shape (...,2 | 3)
Projected coordinates.
Examples
--------
>>> project_stereographic(np.ones(3))
[0.3660254, 0.3660254]
>>> project_stereographic(np.ones(3),direction='x',normalize=False,keepdims=True)
[0, 0.5, 0.5]
>>> project_stereographic([0,1,1],direction='y',normalize=True,keepdims=False)
[0.41421356, 0]
"""
v_ = vector/np.linalg.norm(vector,axis=-1,keepdims=True) if normalize else vector
return np.block([v_[...,:2]/(1+np.abs(v_[...,2:3])),
np.zeros_like(v_[...,2:3])])
shift = 'zyx'.index(direction)
v_ = np.roll(vector/np.linalg.norm(vector,axis=-1,keepdims=True) if normalize else vector,
shift,axis=-1)
return np.roll(np.block([v_[...,:2]/(1+np.abs(v_[...,2:3])),np.zeros_like(v_[...,2:3])]),
-shift if keepdims else 0,axis=-1)[...,:3 if keepdims else 2]
def execution_stamp(class_name,function_name=None):
@ -418,7 +439,7 @@ class _ProgressBar:
bar = '' * filled_length + '' * (self.bar_length - filled_length)
delta_time = datetime.datetime.now() - self.start_time
remaining_time = (self.total - (iteration+1)) * delta_time / (iteration+1)
remaining_time -= datetime.timedelta(microseconds=remaining_time.microseconds) # remove μs
remaining_time -= datetime.timedelta(microseconds=remaining_time.microseconds) # remove μs
sys.stderr.write(f'\r{self.prefix} {bar} {fraction:>4.0%} ETA {remaining_time}')
sys.stderr.flush()

View File

@ -6,28 +6,29 @@ with open(Path(__file__).parent/'damask/VERSION') as f:
version = re.sub(r'(-([^-]*)).*$',r'.\2',re.sub(r'^v(\d+\.\d+(\.\d+)?)',r'\1',f.readline().strip()))
setuptools.setup(
name="damask",
name='damask',
version=version,
author="The DAMASK team",
author_email="damask@mpie.de",
description="DAMASK library",
long_description="Python library for pre and post processing of DAMASK simulations",
url="https://damask.mpie.de",
author='The DAMASK team',
author_email='damask@mpie.de',
description='DAMASK library',
long_description='Python library for pre and post processing of DAMASK simulations',
url='https://damask.mpie.de',
packages=setuptools.find_packages(),
include_package_data=True,
python_requires = '>=3.6',
install_requires = [
"pandas", # requires numpy
"scipy",
"h5py", # requires numpy
"vtk",
"matplotlib", # requires numpy, pillow
"pyaml"
'pandas>=0.24', # requires numpy
'scipy>=1.2',
'h5py>=2.9', # requires numpy
'vtk>=8.1',
'matplotlib>=3.0', # requires numpy, pillow
'pyaml>=3.12'
],
classifiers = [
"Intended Audience :: Science/Research",
"Topic :: Scientific/Engineering",
"Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
"Operating System :: OS Independent",
'Intended Audience :: Science/Research',
'Topic :: Scientific/Engineering',
'Programming Language :: Python :: 3',
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
'Operating System :: OS Independent',
],
)

View File

@ -1,32 +1,32 @@
homogenization:
SX:
N_constituents: 1
mechanics: {type: none}
mechanics: {type: pass}
Taylor:
N_constituents: 2
mechanics: {type: isostrain}
material:
- constituents:
- fraction: 1.0
- v: 1.0
O: [1.0, 0.0, 0.0, 0.0]
phase: Aluminum
homogenization: SX
- constituents:
- fraction: 1.0
- v: 1.0
O: [0.7936696712125002, -0.28765777461664166, -0.3436487135089419, 0.4113964260949434]
phase: Aluminum
homogenization: SX
- constituents:
- fraction: 1.0
- v: 1.0
O: [0.3986143167493579, -0.7014883552495493, 0.2154871765709027, 0.5500781677772945]
phase: Aluminum
homogenization: SX
- constituents:
- fraction: 0.5
- v: 0.5
O: [0.28645844315788244, -0.022571491243423537, -0.467933059311115, -0.8357456192708106]
phase: Aluminum
- fraction: 0.5
- v: 0.5
O: [0.3986143167493579, -0.7014883552495493, 0.2154871765709027, 0.5500781677772945]
phase: Steel
homogenization: Taylor

View File

@ -22,6 +22,19 @@ class TestConfig:
with open(tmp_path/'config.yaml') as f:
assert Config.load(f) == config
def test_add_remove(self):
dummy = {'hello':'world','foo':'bar'}
config = Config()
config |= dummy
assert config == Config() | dummy
config = config.delete(dummy)
assert config == Config()
assert (config | dummy ).delete( 'hello' ) == config | {'foo':'bar'}
assert (config | dummy ).delete([ 'hello', 'foo' ]) == config
assert (config | Config(dummy)).delete({ 'hello':1,'foo':2 }) == config
assert (config | Config(dummy)).delete(Config({'hello':1 })) == config | {'foo':'bar'}
def test_repr(self,tmp_path):
config = Config()
config['A'] = 1

View File

@ -5,6 +5,7 @@ import numpy as np
from damask import ConfigMaterial
from damask import Table
from damask import Rotation
@pytest.fixture
def ref_path(ref_path_base):
@ -42,7 +43,7 @@ class TestConfigMaterial:
def test_invalid_fraction(self,ref_path):
material_config = ConfigMaterial.load(ref_path/'material.yaml')
material_config['material'][0]['constituents'][0]['fraction']=.9
material_config['material'][0]['constituents'][0]['v']=.9
assert not material_config.is_valid
@pytest.mark.parametrize('item',['homogenization','phase','material'])
@ -85,42 +86,25 @@ class TestConfigMaterial:
def test_from_table(self):
N = np.random.randint(3,10)
a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])),np.ones(N*2),np.zeros(N*2),np.ones(N*2))).T
t = Table(a,{'varying':2,'constant':2})
c = ConfigMaterial.from_table(t,constituents={'a':'varying','b':'1_constant'},c='2_constant')
a = np.vstack((np.hstack((np.arange(N),np.arange(N)[::-1])),np.ones(N*2),np.zeros(N*2),np.ones(N*2),np.ones(N*2))).T
t = Table(a,{'varying':1,'constant':4})
c = ConfigMaterial.from_table(t,**{'phase':'varying','O':'constant','homogenization':'4_constant'})
assert len(c['material']) == N
for i,m in enumerate(c['material']):
c = m['constituents'][0]
assert m['c'] == 1 and c['b'] == 0 and (c['a'] == [i,1]).all()
assert m['homogenization'] == 1 and (m['constituents'][0]['O'] == [1,0,1,1]).all()
def test_constituents(self):
c = ConfigMaterial._constituents(c=1,v=[2,3])
assert c[0][0]['c'] == c[1][0]['c'] == 1
assert c[0][0]['v'] == c[1][0]['v'] -1 ==2
@pytest.mark.parametrize('constituents',[{'W':1,'X':[2,3]},{'Y':4},{'Z':[5,6]}])
@pytest.mark.parametrize('a',[[7.,8.],9.])
@pytest.mark.parametrize('b',['bd',['efg','hi']])
def test_material_add(self,tmp_path,constituents,a,b):
len_c = len(ConfigMaterial()._constituents(1,**constituents))
len_a = len(a) if isinstance(a,list) else 1
len_b = len(b) if isinstance(b,list) else 1
m = ConfigMaterial().material_add(constituents,a=a,b=b)
m.save()
assert len(m['material']) == np.max([len_a,len_b,len_c])
@pytest.mark.parametrize('constituents',[{'W':1,'X':np.array([2,3])},{'Y':4},{'Z':np.array([5,6])}])
@pytest.mark.parametrize('a',[np.array([7,8]),9])
def test_material_add_np(self,tmp_path,constituents,a):
len_c = len(ConfigMaterial()._constituents(1,**constituents))
len_a = len(a) if isinstance(a,np.ndarray) else 1
m = ConfigMaterial().material_add(constituents,ld=a)
m.save()
assert len(m['material']) == np.max([len_a,len_c])
@pytest.mark.parametrize('constituents',[{'X':np.array([2,3,4,5])},{'Y':4}])
@pytest.mark.parametrize('a',[np.array([1,2,3]),[4,5,6]])
@pytest.mark.parametrize('b',[np.array([6.,7.]),[8.,9.]])
def test_material_add_invalid(self,constituents,a,b):
with pytest.raises(ValueError):
ConfigMaterial().material_add(constituents,a=a,u=b)
@pytest.mark.parametrize('N,n,kw',[
(1,1,{'phase':'Gold',
'O':[1,0,0,0],
'homogenization':'SX'}),
(3,1,{'phase':'Gold',
'O':Rotation.from_random(3),
'homogenization':'SX'}),
(2,3,{'phase':np.broadcast_to(['a','b','c'],(2,3)),
'O':Rotation.from_random((2,3)),
'homogenization':['SX','PX']}),
])
def test_material_add(self,kw,N,n):
m = ConfigMaterial().material_add(**kw)
assert len(m['material']) == N
assert len(m['material'][0]['constituents']) == n

View File

@ -347,7 +347,7 @@ class TestGrid:
@pytest.mark.parametrize('approach',['Laguerre','Voronoi'])
def test_tessellate_bicrystal(self,approach):
cells = np.random.randint(5,10,3)*2
size = cells.astype(np.float)
size = cells.astype(float)
seeds = np.vstack((size*np.array([0.5,0.25,0.5]),size*np.array([0.5,0.75,0.5])))
material = np.zeros(cells)
material[:,cells[1]//2:,:] = 1

View File

@ -7,6 +7,7 @@ from damask import Orientation
from damask import Table
from damask import lattice
from damask import util
from damask import grid_filters
@pytest.fixture
@ -25,13 +26,16 @@ class TestOrientation:
@pytest.mark.parametrize('shape',[None,5,(4,6)])
def test_equal(self,lattice,shape):
R = Rotation.from_random(shape)
assert Orientation(R,lattice) == Orientation(R,lattice)
assert Orientation(R,lattice) == Orientation(R,lattice) if shape is None else \
(Orientation(R,lattice) == Orientation(R,lattice)).all()
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
@pytest.mark.parametrize('shape',[None,5,(4,6)])
def test_unequal(self,lattice,shape):
R = Rotation.from_random(shape)
assert not(Orientation(R,lattice) != Orientation(R,lattice))
assert not ( Orientation(R,lattice) != Orientation(R,lattice) if shape is None else \
(Orientation(R,lattice) != Orientation(R,lattice)).any())
@pytest.mark.parametrize('a,b',[
(dict(rotation=[1,0,0,0]),
@ -115,7 +119,7 @@ class TestOrientation:
== np.eye(3))
def test_from_cubochoric(self):
assert np.all(Orientation.from_cubochoric(c=np.zeros(3),lattice='triclinic').as_matrix()
assert np.all(Orientation.from_cubochoric(x=np.zeros(3),lattice='triclinic').as_matrix()
== np.eye(3))
def test_from_spherical_component(self):
@ -138,7 +142,7 @@ class TestOrientation:
dict(lattice='hP',a=1.0 ),
dict(lattice='cI',a=1.0, ),
])
def test_from_direction(self,kwargs):
def test_from_directions(self,kwargs):
for a,b in np.random.random((10,2,3)):
c = np.cross(b,a)
if np.all(np.isclose(c,0)): continue
@ -148,6 +152,21 @@ class TestOrientation:
assert np.isclose(np.dot(x/np.linalg.norm(x),np.array([1,0,0])),1) \
and np.isclose(np.dot(z/np.linalg.norm(z),np.array([0,0,1])),1)
@pytest.mark.parametrize('function',[Orientation.from_random,
Orientation.from_quaternion,
Orientation.from_Euler_angles,
Orientation.from_axis_angle,
Orientation.from_basis,
Orientation.from_matrix,
Orientation.from_Rodrigues_vector,
Orientation.from_homochoric,
Orientation.from_cubochoric,
Orientation.from_spherical_component,
Orientation.from_fiber_component,
Orientation.from_directions])
def test_invalid_from(self,function):
with pytest.raises(TypeError):
function(c=.1,degrees=True,invalid=66)
def test_negative_angle(self):
with pytest.raises(ValueError):
@ -218,6 +237,16 @@ class TestOrientation:
for r, theO in zip(o.reduced.flatten(),o.flatten()):
assert r == theO.reduced
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
def test_reduced_corner_cases(self,lattice):
# test whether there is always a sym-eq rotation that falls into the FZ
N = np.random.randint(10,40)
size = np.ones(3)*np.pi**(2./3.)
grid = grid_filters.coordinates0_node([N+1,N+1,N+1],size,-size*.5)
evenly_distributed = Orientation.from_cubochoric(x=grid[:-2,:-2,:-2],lattice=lattice)
assert evenly_distributed.shape == evenly_distributed.reduced.shape
@pytest.mark.parametrize('lattice',Orientation.crystal_families)
@pytest.mark.parametrize('shape',[(1),(2,3),(4,3,2)])
@pytest.mark.parametrize('vector',np.array([[1,0,0],[1,2,3],[-1,1,-1]]))
@ -403,7 +432,7 @@ class TestOrientation:
def test_relationship_vectorize(self,set_of_quaternions,lattice,model):
r = Orientation(rotation=set_of_quaternions[:200].reshape((50,4,4)),lattice=lattice).related(model)
for i in range(200):
assert r.reshape((-1,200))[:,i] == Orientation(set_of_quaternions[i],lattice).related(model)
assert (r.reshape((-1,200))[:,i] == Orientation(set_of_quaternions[i],lattice).related(model)).all()
@pytest.mark.parametrize('model',['Bain','KS','GT','GT_prime','NW','Pitsch'])
@pytest.mark.parametrize('lattice',['cF','cI'])

View File

@ -21,7 +21,7 @@ def default(tmp_path,ref_path):
fname = '12grains6x7x8_tensionY.hdf5'
shutil.copy(ref_path/fname,tmp_path)
f = Result(tmp_path/fname)
f.pick('times',20.0)
f.view('times',20.0)
return f
@pytest.fixture
@ -43,56 +43,56 @@ class TestResult:
print(default)
def test_pick_all(self,default):
default.pick('increments',True)
def test_view_all(self,default):
default.view('increments',True)
a = default.get_dataset_location('F')
default.pick('increments','*')
default.view('increments','*')
b = default.get_dataset_location('F')
default.pick('increments',default.incs_in_range(0,np.iinfo(int).max))
default.view('increments',default.incs_in_range(0,np.iinfo(int).max))
c = default.get_dataset_location('F')
default.pick('times',True)
default.view('times',True)
d = default.get_dataset_location('F')
default.pick('times','*')
default.view('times','*')
e = default.get_dataset_location('F')
default.pick('times',default.times_in_range(0.0,np.inf))
default.view('times',default.times_in_range(0.0,np.inf))
f = default.get_dataset_location('F')
assert a == b == c == d == e ==f
@pytest.mark.parametrize('what',['increments','times','phases']) # ToDo: discuss homogenizations
def test_pick_none(self,default,what):
default.pick(what,False)
def test_view_none(self,default,what):
default.view(what,False)
a = default.get_dataset_location('F')
default.pick(what,[])
default.view(what,[])
b = default.get_dataset_location('F')
assert a == b == []
@pytest.mark.parametrize('what',['increments','times','phases']) # ToDo: discuss homogenizations
def test_pick_more(self,default,what):
default.pick(what,False)
default.pick_more(what,'*')
def test_view_more(self,default,what):
default.view(what,False)
default.view_more(what,'*')
a = default.get_dataset_location('F')
default.pick(what,True)
default.view(what,True)
b = default.get_dataset_location('F')
assert a == b
@pytest.mark.parametrize('what',['increments','times','phases']) # ToDo: discuss homogenizations
def test_pick_less(self,default,what):
default.pick(what,True)
default.pick_less(what,'*')
def test_view_less(self,default,what):
default.view(what,True)
default.view_less(what,'*')
a = default.get_dataset_location('F')
default.pick(what,False)
default.view(what,False)
b = default.get_dataset_location('F')
assert a == b == []
def test_pick_invalid(self,default):
def test_view_invalid(self,default):
with pytest.raises(AttributeError):
default.pick('invalid',True)
default.view('invalid',True)
def test_add_absolute(self,default):
default.add_absolute('F_e')
@ -307,7 +307,7 @@ class TestResult:
@pytest.mark.parametrize('overwrite',['off','on'])
def test_add_overwrite(self,default,overwrite):
default.pick('times',default.times_in_range(0,np.inf)[-1])
default.view('times',default.times_in_range(0,np.inf)[-1])
default.add_stress_Cauchy()
loc = default.get_dataset_location('sigma')

View File

@ -526,7 +526,7 @@ class TestRotation:
o = backward(forward(m))
u = np.array([np.pi*2,np.pi,np.pi*2])
ok = np.allclose(m,o,atol=atol)
ok = ok or np.allclose(np.where(np.isclose(m,u),m-u,m),np.where(np.isclose(o,u),o-u,o),atol=atol)
ok |= np.allclose(np.where(np.isclose(m,u),m-u,m),np.where(np.isclose(o,u),o-u,o),atol=atol)
if np.isclose(m[1],0.0,atol=atol) or np.isclose(m[1],np.pi,atol=atol):
sum_phi = np.unwrap([m[0]+m[2],o[0]+o[2]])
ok |= np.isclose(sum_phi[0],sum_phi[1],atol=atol)
@ -550,19 +550,22 @@ class TestRotation:
assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) and o[3]<=np.pi+1.e-9, f'{m},{o},{rot.as_quaternion()}'
@pytest.mark.parametrize('forward,backward',[(Rotation._ro2qu,Rotation._qu2ro),
#(Rotation._ro2om,Rotation._om2ro),
#(Rotation._ro2eu,Rotation._eu2ro),
(Rotation._ro2om,Rotation._om2ro),
(Rotation._ro2eu,Rotation._eu2ro),
(Rotation._ro2ax,Rotation._ax2ro),
(Rotation._ro2ho,Rotation._ho2ro),
(Rotation._ro2cu,Rotation._cu2ro)])
def test_Rodrigues_internal(self,set_of_rotations,forward,backward):
"""Ensure invariance of conversion from Rodrigues-Frank vector and back."""
cutoff = np.tan(np.pi*.5*(1.-1e-4))
cutoff = np.tan(np.pi*.5*(1.-1e-5))
for rot in set_of_rotations:
m = rot.as_Rodrigues_vector()
o = backward(forward(m))
ok = np.allclose(np.clip(m,None,cutoff),np.clip(o,None,cutoff),atol=atol)
ok = ok or np.isclose(m[3],0.0,atol=atol)
ok |= np.isclose(m[3],0.0,atol=atol)
if m[3] > cutoff:
ok |= np.allclose(m[:3],-1*o[:3])
assert ok and np.isclose(np.linalg.norm(o[:3]),1.0), f'{m},{o},{rot.as_quaternion()}'
@pytest.mark.parametrize('forward,backward',[(Rotation._ho2qu,Rotation._qu2ho),
@ -592,7 +595,7 @@ class TestRotation:
o = backward(forward(m))
ok = np.allclose(m,o,atol=atol)
if np.count_nonzero(np.isclose(np.abs(o),np.pi**(2./3.)*.5)):
ok = ok or np.allclose(m*-1.,o,atol=atol)
ok |= np.allclose(m*-1.,o,atol=atol)
assert ok and np.max(np.abs(o)) < np.pi**(2./3.) * 0.5 + 1.e-9, f'{m},{o},{rot.as_quaternion()}'
@pytest.mark.parametrize('vectorized, single',[(Rotation._qu2om,qu2om),
@ -686,6 +689,10 @@ class TestRotation:
with pytest.raises(TypeError):
Rotation(np.ones(3))
def test_to_numpy(self):
r = Rotation.from_random(np.random.randint(0,10,4))
assert np.all(r.as_quaternion() == np.array(r))
@pytest.mark.parametrize('degrees',[True,False])
def test_Eulers(self,set_of_rotations,degrees):
for rot in set_of_rotations:
@ -719,7 +726,7 @@ class TestRotation:
o = Rotation.from_axis_angle(rot.as_axis_angle()).as_axis_angle()
ok = np.allclose(m,o,atol=atol)
if np.isclose(m[3],np.pi,atol=atol):
ok = ok or np.allclose(m*np.array([-1.,-1.,-1.,1.]),o,atol=atol)
ok |= np.allclose(m*np.array([-1.,-1.,-1.,1.]),o,atol=atol)
assert ok and np.isclose(np.linalg.norm(o[:3]),1.0) \
and o[3]<=np.pi+1.e-9, f'{m},{o},{rot.as_quaternion()}'
@ -740,7 +747,7 @@ class TestRotation:
m = rot.as_Rodrigues_vector()
o = Rotation.from_homochoric(rot.as_homochoric()*P*-1,P).as_Rodrigues_vector()
ok = np.allclose(np.clip(m,None,cutoff),np.clip(o,None,cutoff),atol=atol)
ok = ok or np.isclose(m[3],0.0,atol=atol)
ok |= np.isclose(m[3],0.0,atol=atol)
assert ok and np.isclose(np.linalg.norm(o[:3]),1.0), f'{m},{o},{rot.as_quaternion()}'
@pytest.mark.parametrize('P',[1,-1])
@ -780,14 +787,32 @@ class TestRotation:
else:
assert r.shape == shape
def test_equal(self):
assert Rotation.from_random(rng_seed=1) == Rotation.from_random(rng_seed=1)
@pytest.mark.parametrize('shape',[None,5,(4,6)])
def test_equal(self,shape):
R = Rotation.from_random(shape,rng_seed=1)
assert R == R if shape is None else (R == R).all()
@pytest.mark.parametrize('shape',[None,5,(4,6)])
def test_unequal(self,shape):
R = Rotation.from_random(shape,rng_seed=1)
assert not (R != R if shape is None else (R != R).any())
def test_equal_ambiguous(self):
qu = np.random.rand(10,4)
qu[:,0] = 0.
qu/=np.linalg.norm(qu,axis=1,keepdims=True)
assert (Rotation(qu) == Rotation(-qu)).all()
def test_inversion(self):
r = Rotation.from_random()
assert r == ~~r
@pytest.mark.parametrize('shape',[None,1,(1,),(4,2),(1,1,1)])
@pytest.mark.parametrize('shape',[1,(1,),(4,2),(1,1,1),tuple(np.random.randint(0,10,4))])
def test_size(self,shape):
assert Rotation.from_random(shape).size == np.prod(shape)
@pytest.mark.parametrize('shape',[None,1,(1,),(4,2),(1,1,1),tuple(np.random.randint(0,10,4))])
def test_shape(self,shape):
r = Rotation.from_random(shape=shape)
assert r.shape == (shape if isinstance(shape,tuple) else (shape,) if shape else ())
@ -798,7 +823,7 @@ class TestRotation:
p = Rotation.from_random(shape=shape)
s = r.append(p)
print(f'append 2x {shape} --> {s.shape}')
assert s[0,...] == r[0,...] and s[-1,...] == p[-1,...]
assert np.logical_and(s[0,...] == r[0,...], s[-1,...] == p[-1,...]).all()
@pytest.mark.parametrize('shape',[None,1,(1,),(4,2),(3,3,2)])
def test_append_list(self,shape):
@ -806,7 +831,7 @@ class TestRotation:
p = Rotation.from_random(shape=shape)
s = r.append([r,p])
print(f'append 3x {shape} --> {s.shape}')
assert s[0,...] == r[0,...] and s[-1,...] == p[-1,...]
assert np.logical_and(s[0,...] == r[0,...], s[-1,...] == p[-1,...]).all()
@pytest.mark.parametrize('quat,standardized',[
([-1,0,0,0],[1,0,0,0]),
@ -828,7 +853,7 @@ class TestRotation:
@pytest.mark.parametrize('order',['C','F'])
def test_flatten_reshape(self,shape,order):
r = Rotation.from_random(shape=shape)
assert r == r.flatten(order).reshape(shape,order)
assert (r == r.flatten(order).reshape(shape,order)).all()
@pytest.mark.parametrize('function',[Rotation.from_quaternion,
Rotation.from_Euler_angles,
@ -939,7 +964,7 @@ class TestRotation:
def test_rotate_inverse(self):
R = Rotation.from_random()
assert np.allclose(np.eye(3),(~R@R).as_matrix())
assert np.allclose(np.eye(3),(~R*R).as_matrix())
@pytest.mark.parametrize('data',[np.random.rand(3),
np.random.rand(3,3),
@ -973,6 +998,42 @@ class TestRotation:
R_2 = Rotation.from_Euler_angles([360,0,0],degrees=True)
assert np.allclose(R_1.misorientation(R_2).as_matrix(),np.eye(3))
def test_composition(self):
a,b = (Rotation.from_random(),Rotation.from_random())
c = a * b
a *= b
assert c == a
def test_composition_invalid(self):
with pytest.raises(TypeError):
Rotation()*np.ones(3)
def test_composition_inverse(self):
a,b = (Rotation.from_random(),Rotation.from_random())
c = a / b
a /= b
assert c == a
def test_composition_inverse_invalid(self):
with pytest.raises(TypeError):
Rotation()/np.ones(3)
def test_power(self):
a = Rotation.from_random()
r = (np.random.rand()-.5)*4
b = a**r
a **= r
assert a == b
def test_invariant(self):
R = Rotation.from_random()
assert R/R == R*R**(-1) == Rotation()
@pytest.mark.parametrize('item',[np.ones(3),np.ones((3,3)), np.ones((3,3,3,3))])
def test_apply(self,item):
r = Rotation.from_random()
assert (r.apply(item) == r@item).all()
@pytest.mark.parametrize('angle',[10,20,30,40,50,60,70,80,90,100,120])
def test_average(self,angle):
R = Rotation.from_axis_angle([[0,0,1,10],[0,0,1,angle]],degrees=True)

View File

@ -49,17 +49,18 @@ class TestUtil:
dist_sampled = np.histogram(centers[selected],bins)[0]/N_samples*np.sum(dist)
assert np.sqrt(((dist - dist_sampled) ** 2).mean()) < .025 and selected.shape[0]==N_samples
@pytest.mark.parametrize('point,normalize,answer',
@pytest.mark.parametrize('point,direction,normalize,keepdims,answer',
[
([1,0,0],False,[1,0,0]),
([1,0,0],True, [1,0,0]),
([0,1,1],False,[0,0.5,0]),
([0,1,1],True, [0,0.41421356,0]),
([1,1,1],False,[0.5,0.5,0]),
([1,1,1],True, [0.3660254, 0.3660254, 0]),
([1,0,0],'z',False,True, [1,0,0]),
([1,0,0],'z',True, False,[1,0]),
([0,1,1],'z',False,True, [0,0.5,0]),
([0,1,1],'y',True, False,[0.41421356,0]),
([1,1,0],'x',False,False,[0.5,0]),
([1,1,1],'y',True, True, [0.3660254, 0,0.3660254]),
])
def test_project_stereographic(self,point,normalize,answer):
assert np.allclose(util.project_stereographic(np.array(point),normalize=normalize),answer)
def test_project_stereographic(self,point,direction,normalize,keepdims,answer):
assert np.allclose(util.project_stereographic(np.array(point),direction=direction,
normalize=normalize,keepdims=keepdims),answer)
@pytest.mark.parametrize('fro,to,mode,answer',
[

View File

@ -19,7 +19,7 @@ module CPFEM
use HDF5_utilities
use results
use lattice
use constitutive
use phase
implicit none
private
@ -72,7 +72,6 @@ contains
!--------------------------------------------------------------------------------------------------
subroutine CPFEM_initAll
call parallelization_init
call DAMASK_interface_init
call prec_init
call IO_init
@ -86,7 +85,7 @@ subroutine CPFEM_initAll
call discretization_marc_init
call lattice_init
call material_init(.false.)
call constitutive_init
call phase_init
call homogenization_init
call crystallite_init
call CPFEM_init
@ -179,11 +178,11 @@ subroutine CPFEM_general(mode, ffn, ffn1, temperature_inp, dt, elFE, ip, cauchyS
if (iand(mode, CPFEM_AGERESULTS) /= 0_pInt) call CPFEM_forward
chosenThermal1: select case (thermal_type(material_homogenizationAt(elCP)))
case (THERMAL_conduction_ID) chosenThermal1
temperature(material_homogenizationAt(elCP))%p(material_homogenizationMemberAt(ip,elCP)) = &
temperature_inp
end select chosenThermal1
!chosenThermal1: select case (thermal_type(material_homogenizationAt(elCP)))
! case (THERMAL_conduction_ID) chosenThermal1
! temperature(material_homogenizationAt(elCP))%p(material_homogenizationMemberAt(ip,elCP)) = &
! temperature_inp
!end select chosenThermal1
homogenization_F0(1:3,1:3,ma) = ffn
homogenization_F(1:3,1:3,ma) = ffn1
@ -258,7 +257,7 @@ end subroutine CPFEM_general
subroutine CPFEM_forward
call homogenization_forward
call constitutive_forward
call phase_forward
end subroutine CPFEM_forward
@ -273,7 +272,7 @@ subroutine CPFEM_results(inc,time)
call results_openJobFile
call results_addIncrement(inc,time)
call constitutive_results
call phase_results
call homogenization_results
call discretization_results
call results_finalizeIncrement

View File

@ -19,7 +19,7 @@ module CPFEM2
use discretization
use HDF5_utilities
use homogenization
use constitutive
use phase
#if defined(Mesh)
use FEM_quadrature
use discretization_mesh
@ -60,7 +60,7 @@ subroutine CPFEM_initAll
call discretization_grid_init(restart=interface_restartInc>0)
#endif
call material_init(restart=interface_restartInc>0)
call constitutive_init
call phase_init
call homogenization_init
call crystallite_init
call CPFEM_init
@ -74,9 +74,22 @@ end subroutine CPFEM_initAll
!--------------------------------------------------------------------------------------------------
subroutine CPFEM_init
integer(HID_T) :: fileHandle
print'(/,a)', ' <<<+- CPFEM init -+>>>'; flush(IO_STDOUT)
if (interface_restartInc > 0) call crystallite_restartRead
if (interface_restartInc > 0) then
print'(/,a,i0,a)', ' reading restart information of increment from file'; flush(IO_STDOUT)
fileHandle = HDF5_openFile(getSolverJobName()//'_restart.hdf5','r')
call homogenization_restartRead(fileHandle)
call phase_restartRead(fileHandle)
call HDF5_closeFile(fileHandle)
endif
end subroutine CPFEM_init
@ -86,7 +99,17 @@ end subroutine CPFEM_init
!--------------------------------------------------------------------------------------------------
subroutine CPFEM_restartWrite
call crystallite_restartWrite
integer(HID_T) :: fileHandle
print*, ' writing field and constitutive data required for restart to file';flush(IO_STDOUT)
fileHandle = HDF5_openFile(getSolverJobName()//'_restart.hdf5','a')
call homogenization_restartWrite(fileHandle)
call phase_restartWrite(fileHandle)
call HDF5_closeFile(fileHandle)
end subroutine CPFEM_restartWrite
@ -97,7 +120,7 @@ end subroutine CPFEM_restartWrite
subroutine CPFEM_forward
call homogenization_forward
call constitutive_forward
call phase_forward
end subroutine CPFEM_forward
@ -112,7 +135,7 @@ subroutine CPFEM_results(inc,time)
call results_openJobFile
call results_addIncrement(inc,time)
call constitutive_results
call phase_results
call homogenization_results
call discretization_results
call results_finalizeIncrement

View File

@ -43,7 +43,7 @@ void gethostname_c(char hostname[], int *stat){
void getusername_c(char username[], int *stat){
struct passwd *pw = getpwuid(geteuid());
struct passwd *pw = getpwuid(getuid());
if(pw && strlen(pw->pw_name) <= STRLEN){
strncpy(username,pw->pw_name,STRLEN+1);
*stat = 0;

View File

@ -199,7 +199,7 @@ subroutine DAMASK_interface_init
if (interface_restartInc > 0) &
print'(a,i6.6)', ' Restart from increment: ', interface_restartInc
!call signalterm_c(c_funloc(catchSIGTERM))
call signalterm_c(c_funloc(catchSIGTERM))
call signalusr1_c(c_funloc(catchSIGUSR1))
call signalusr2_c(c_funloc(catchSIGUSR2))
call interface_setSIGTERM(.false.)
@ -386,24 +386,14 @@ end function makeRelativePath
subroutine catchSIGTERM(signal) bind(C)
integer(C_INT), value :: signal
print'(a,i0)', ' received signal ',signal
call interface_setSIGTERM(.true.)
print'(a,i0,a)', ' received signal ',signal, ', set SIGTERM=TRUE'
end subroutine catchSIGTERM
!--------------------------------------------------------------------------------------------------
!> @brief Set global variable interface_SIGTERM.
!--------------------------------------------------------------------------------------------------
subroutine interface_setSIGTERM(state)
logical, intent(in) :: state
interface_SIGTERM = state
end subroutine interface_setSIGTERM
!--------------------------------------------------------------------------------------------------
!> @brief Set global variable interface_SIGUSR1 to .true.
!> @details This function can be registered to catch signals send to the executable.
@ -411,24 +401,14 @@ end subroutine interface_setSIGTERM
subroutine catchSIGUSR1(signal) bind(C)
integer(C_INT), value :: signal
print'(a,i0)', ' received signal ',signal
call interface_setSIGUSR1(.true.)
print'(a,i0,a)', ' received signal ',signal, ', set SIGUSR1=TRUE'
end subroutine catchSIGUSR1
!--------------------------------------------------------------------------------------------------
!> @brief Set global variable interface_SIGUSR.
!--------------------------------------------------------------------------------------------------
subroutine interface_setSIGUSR1(state)
logical, intent(in) :: state
interface_SIGUSR1 = state
end subroutine interface_setSIGUSR1
!--------------------------------------------------------------------------------------------------
!> @brief Set global variable interface_SIGUSR2 to .true.
!> @details This function can be registered to catch signals send to the executable.
@ -436,20 +416,52 @@ end subroutine interface_setSIGUSR1
subroutine catchSIGUSR2(signal) bind(C)
integer(C_INT), value :: signal
print'(a,i0,a)', ' received signal ',signal
call interface_setSIGUSR2(.true.)
print'(a,i0,a)', ' received signal ',signal, ', set SIGUSR2=TRUE'
end subroutine catchSIGUSR2
!--------------------------------------------------------------------------------------------------
!> @brief Set global variable interface_SIGTERM.
!--------------------------------------------------------------------------------------------------
subroutine interface_setSIGTERM(state)
logical, intent(in) :: state
interface_SIGTERM = state
print*, 'set SIGTERM to',state
end subroutine interface_setSIGTERM
!--------------------------------------------------------------------------------------------------
!> @brief Set global variable interface_SIGUSR.
!--------------------------------------------------------------------------------------------------
subroutine interface_setSIGUSR1(state)
logical, intent(in) :: state
interface_SIGUSR1 = state
print*, 'set SIGUSR1 to',state
end subroutine interface_setSIGUSR1
!--------------------------------------------------------------------------------------------------
!> @brief Set global variable interface_SIGUSR2.
!--------------------------------------------------------------------------------------------------
subroutine interface_setSIGUSR2(state)
logical, intent(in) :: state
interface_SIGUSR2 = state
print*, 'set SIGUSR2 to',state
end subroutine interface_setSIGUSR2

View File

@ -7,20 +7,6 @@
!> @author Christoph Kords, Max-Planck-Institut für Eisenforschung GmbH
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
!> @brief Interfaces DAMASK with 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 - 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 - uedinc
!> @details - flux
!> @details - quit
!> @details Marc common blocks included:
!> @details - concom: lovl, inc
!> @details - creeps: timinc
!--------------------------------------------------------------------------------------------------
#define QUOTE(x) #x
#define PASTE(x,y) x ## y
@ -65,14 +51,8 @@ subroutine DAMASK_interface_init
print'(/,a)', ' Version: '//DAMASKVERSION
! https://github.com/jeffhammond/HPCInfo/blob/master/docs/Preprocessor-Macros.md
#if __INTEL_COMPILER >= 1800
print'(/,a)', ' Compiled with: '//compiler_version()
print'(a)', ' Compiler options: '//compiler_options()
#else
print'(/,a,i4.4,a,i8.8)', ' Compiled with Intel fortran version :', __INTEL_COMPILER,&
', build date :', __INTEL_COMPILER_BUILD_DATE
#endif
print'(/,a)', ' Compiled with: '//compiler_version()
print'(a)', ' Compiler options: '//compiler_options()
print'(/,a)', ' Compiled on: '//__DATE__//' at '//__TIME__
@ -239,7 +219,7 @@ subroutine hypela2(d,g,e,de,s,t,dt,ngens,m,nn,kcus,matus,ndi,nshear,disp, &
real(pReal), dimension(6) :: stress
real(pReal), dimension(6,6) :: ddsdde
integer :: computationMode, i, cp_en, node, CPnodeID
integer(4) :: defaultNumThreadsInt !< default value set by Marc
integer(pI32) :: defaultNumThreadsInt !< default value set by Marc
integer(pInt), save :: &
theInc = -1_pInt, & !< needs description
@ -250,13 +230,13 @@ subroutine hypela2(d,g,e,de,s,t,dt,ngens,m,nn,kcus,matus,ndi,nshear,disp, &
logical, save :: &
lastIncConverged = .false., & !< needs description
outdatedByNewInc = .false., & !< needs description
CPFEM_init_done = .false., & !< remember whether init has been done already
CPFEM_init_done = .false., & !< remember whether init has been done already
debug_basic = .true.
class(tNode), pointer :: &
debug_Marc ! pointer to Marc debug options
if(debug_basic) then
print'(a,/,i8,i8,i2)', ' MSC.MARC information on shape of element(2), IP:', m, nn
print'(a,/,i8,i8,i2)', ' MSC.Marc information on shape of element(2), IP:', m, nn
print'(a,2(i1))', ' Jacobian: ', ngens,ngens
print'(a,i1)', ' Direct stress: ', ndi
print'(a,i1)', ' Shear stress: ', nshear
@ -271,7 +251,7 @@ subroutine hypela2(d,g,e,de,s,t,dt,ngens,m,nn,kcus,matus,ndi,nshear,disp, &
endif
defaultNumThreadsInt = omp_get_num_threads() ! remember number of threads set by Marc
call omp_set_num_threads(1) ! no openMP
call omp_set_num_threads(1_pI32) ! no openMP
if (.not. CPFEM_init_done) then
CPFEM_init_done = .true.
@ -351,7 +331,7 @@ end subroutine hypela2
!--------------------------------------------------------------------------------------------------
subroutine flux(f,ts,n,time)
use prec
use thermal_conduction
use homogenization
use discretization_marc
implicit none
@ -364,7 +344,8 @@ subroutine flux(f,ts,n,time)
real(pReal), dimension(2), intent(out) :: &
f
call thermal_conduction_getSourceAndItsTangent(f(1), f(2), ts(3), n(3),mesh_FEM2DAMASK_elem(n(1)))
f(2) = 0.0_pReal
call thermal_conduction_getSource(f(1), n(3),mesh_FEM2DAMASK_elem(n(1)))
end subroutine flux
@ -378,14 +359,28 @@ subroutine flux(f,ts,n,time)
subroutine uedinc(inc,incsub)
use prec
use CPFEM
use discretization_marc
implicit none
integer, intent(in) :: inc, incsub
integer :: n, nqncomp, nqdatatype
integer, save :: inc_written
real(pReal), allocatable, dimension(:,:) :: d_n
#include QUOTE(PASTE(./marc/include/creeps,Marc4DAMASK)) ! creeps is needed for timinc (time increment)
if (inc > inc_written) then
allocate(d_n(3,count(mesh_FEM2DAMASK_node /= -1)))
do n = lbound(mesh_FEM2DAMASK_node,1), ubound(mesh_FEM2DAMASK_node,1)
if (mesh_FEM2DAMASK_node(n) /= -1) then
call nodvar(1,n,d_n(1:3,mesh_FEM2DAMASK_node(n)),nqncomp,nqdatatype)
if(nqncomp == 2) d_n(3,mesh_FEM2DAMASK_node(n)) = 0.0_pReal
endif
enddo
call discretization_marc_UpdateNodeAndIpCoords(d_n)
call CPFEM_results(inc,cptim)
inc_written = inc
endif

View File

@ -71,6 +71,12 @@ module HDF5_utilities
module procedure HDF5_addAttribute_real_array
end interface HDF5_addAttribute
#ifdef PETSc
logical, parameter, private :: parallel_default = .true.
#else
logical, parameter, private :: parallel_default = .false.
#endif
contains
@ -105,16 +111,16 @@ end subroutine HDF5_utilities_init
!--------------------------------------------------------------------------------------------------
!> @brief open and initializes HDF5 output file
!--------------------------------------------------------------------------------------------------
integer(HID_T) function HDF5_openFile(fileName,mode,parallel)
integer(HID_T) function HDF5_openFile(fileName,mode)
character(len=*), intent(in) :: fileName
character, intent(in), optional :: mode
logical, intent(in), optional :: parallel
character :: m
integer(HID_T) :: plist_id
integer :: hdferr
if (present(mode)) then
m = mode
else
@ -125,10 +131,8 @@ integer(HID_T) function HDF5_openFile(fileName,mode,parallel)
if(hdferr < 0) error stop 'HDF5 error'
#ifdef PETSc
if (present(parallel)) then; if (parallel) then
call h5pset_fapl_mpio_f(plist_id, PETSC_COMM_WORLD, MPI_INFO_NULL, hdferr)
if(hdferr < 0) error stop 'HDF5 error'
endif; endif
call h5pset_fapl_mpio_f(plist_id, PETSC_COMM_WORLD, MPI_INFO_NULL, hdferr)
if(hdferr < 0) error stop 'HDF5 error'
#endif
if (m == 'w') then
@ -547,7 +551,7 @@ subroutine HDF5_read_real1(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,&
@ -587,7 +591,7 @@ subroutine HDF5_read_real2(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,&
@ -627,7 +631,7 @@ subroutine HDF5_read_real3(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,&
@ -667,7 +671,7 @@ subroutine HDF5_read_real4(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,&
@ -707,7 +711,7 @@ subroutine HDF5_read_real5(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,&
@ -747,7 +751,7 @@ subroutine HDF5_read_real6(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,&
@ -787,7 +791,7 @@ subroutine HDF5_read_real7(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_DOUBLE,dataset,totalShape, hdferr,&
@ -829,7 +833,7 @@ subroutine HDF5_read_int1(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,&
@ -869,7 +873,7 @@ subroutine HDF5_read_int2(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,&
@ -909,7 +913,7 @@ subroutine HDF5_read_int3(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,&
@ -949,7 +953,7 @@ subroutine HDF5_read_int4(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,&
@ -989,7 +993,7 @@ subroutine HDF5_read_int5(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,&
@ -1029,7 +1033,7 @@ subroutine HDF5_read_int6(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,&
@ -1069,7 +1073,7 @@ subroutine HDF5_read_int7(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,parallel)
else
call initialize_read(dset_id, filespace_id, memspace_id, plist_id, aplist_id, &
myStart, totalShape, loc_id,myShape,datasetName,.false.)
myStart, totalShape, loc_id,myShape,datasetName,parallel_default)
endif
call h5dread_f(dset_id, H5T_NATIVE_INTEGER,dataset,totalShape, hdferr,&
@ -1086,9 +1090,9 @@ end subroutine HDF5_read_int7
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_real1(loc_id,dataset,datasetName,parallel)
real(pReal), intent(inout), dimension(:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
real(pReal), intent(in), dimension(:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1109,7 +1113,7 @@ subroutine HDF5_write_real1(loc_id,dataset,datasetName,parallel)
myStart, totalShape,loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape,loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,.false.)
myStart, totalShape,loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel_default)
endif
if (product(totalShape) /= 0) then
@ -1127,9 +1131,9 @@ end subroutine HDF5_write_real1
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_real2(loc_id,dataset,datasetName,parallel)
real(pReal), intent(inout), dimension(:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
real(pReal), intent(in), dimension(:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1150,7 +1154,7 @@ subroutine HDF5_write_real2(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,.false.)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel_default)
endif
if (product(totalShape) /= 0) then
@ -1168,9 +1172,9 @@ end subroutine HDF5_write_real2
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_real3(loc_id,dataset,datasetName,parallel)
real(pReal), intent(inout), dimension(:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
real(pReal), intent(in), dimension(:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1191,7 +1195,7 @@ subroutine HDF5_write_real3(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,.false.)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel_default)
endif
if (product(totalShape) /= 0) then
@ -1209,9 +1213,9 @@ end subroutine HDF5_write_real3
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_real4(loc_id,dataset,datasetName,parallel)
real(pReal), intent(inout), dimension(:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
real(pReal), intent(in), dimension(:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1232,7 +1236,7 @@ subroutine HDF5_write_real4(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,.false.)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel_default)
endif
if (product(totalShape) /= 0) then
@ -1251,9 +1255,9 @@ end subroutine HDF5_write_real4
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_real5(loc_id,dataset,datasetName,parallel)
real(pReal), intent(inout), dimension(:,:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
real(pReal), intent(in), dimension(:,:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1274,7 +1278,7 @@ subroutine HDF5_write_real5(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,.false.)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel_default)
endif
if (product(totalShape) /= 0) then
@ -1292,9 +1296,9 @@ end subroutine HDF5_write_real5
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_real6(loc_id,dataset,datasetName,parallel)
real(pReal), intent(inout), dimension(:,:,:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
real(pReal), intent(in), dimension(:,:,:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1315,7 +1319,7 @@ subroutine HDF5_write_real6(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,.false.)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel_default)
endif
if (product(totalShape) /= 0) then
@ -1333,9 +1337,9 @@ end subroutine HDF5_write_real6
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_real7(loc_id,dataset,datasetName,parallel)
real(pReal), intent(inout), dimension(:,:,:,:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
real(pReal), intent(in), dimension(:,:,:,:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1356,7 +1360,7 @@ subroutine HDF5_write_real7(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,.false.)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_DOUBLE,parallel_default)
endif
if (product(totalShape) /= 0) then
@ -1375,9 +1379,9 @@ end subroutine HDF5_write_real7
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_int1(loc_id,dataset,datasetName,parallel)
integer, intent(inout), dimension(:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
integer, intent(in), dimension(:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1398,7 +1402,7 @@ subroutine HDF5_write_int1(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,.false.)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel_default)
endif
if (product(totalShape) /= 0) then
@ -1416,9 +1420,9 @@ end subroutine HDF5_write_int1
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_int2(loc_id,dataset,datasetName,parallel)
integer, intent(inout), dimension(:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
integer, intent(in), dimension(:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1439,7 +1443,7 @@ subroutine HDF5_write_int2(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,.false.)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel_default)
endif
if (product(totalShape) /= 0) then
@ -1457,9 +1461,9 @@ end subroutine HDF5_write_int2
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_int3(loc_id,dataset,datasetName,parallel)
integer, intent(inout), dimension(:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
integer, intent(in), dimension(:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1480,7 +1484,7 @@ subroutine HDF5_write_int3(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,.false.)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel_default)
endif
if (product(totalShape) /= 0) then
@ -1498,9 +1502,9 @@ end subroutine HDF5_write_int3
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_int4(loc_id,dataset,datasetName,parallel)
integer, intent(inout), dimension(:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
integer, intent(in), dimension(:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1521,7 +1525,7 @@ subroutine HDF5_write_int4(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,.false.)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel_default)
endif
if (product(totalShape) /= 0) then
@ -1539,9 +1543,9 @@ end subroutine HDF5_write_int4
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_int5(loc_id,dataset,datasetName,parallel)
integer, intent(inout), dimension(:,:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
integer, intent(in), dimension(:,:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1562,7 +1566,7 @@ subroutine HDF5_write_int5(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,.false.)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel_default)
endif
if (product(totalShape) /= 0) then
@ -1580,9 +1584,9 @@ end subroutine HDF5_write_int5
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_int6(loc_id,dataset,datasetName,parallel)
integer, intent(inout), dimension(:,:,:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
integer, intent(in), dimension(:,:,:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1603,7 +1607,7 @@ subroutine HDF5_write_int6(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,.false.)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel_default)
endif
if (product(totalShape) /= 0) then
@ -1621,9 +1625,9 @@ end subroutine HDF5_write_int6
!--------------------------------------------------------------------------------------------------
subroutine HDF5_write_int7(loc_id,dataset,datasetName,parallel)
integer, intent(inout), dimension(:,:,:,:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
integer, intent(in), dimension(:,:,:,:,:,:,:) :: dataset !< data written to file
integer(HID_T), intent(in) :: loc_id !< file or group handle
character(len=*), intent(in) :: datasetName !< name of the dataset in the file
logical, intent(in), optional :: parallel !< dataset is distributed over multiple processes
@ -1644,7 +1648,7 @@ subroutine HDF5_write_int7(loc_id,dataset,datasetName,parallel)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel)
else
call initialize_write(dset_id, filespace_id, memspace_id, plist_id, &
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,.false.)
myStart, totalShape, loc_id,myShape,datasetName,H5T_NATIVE_INTEGER,parallel_default)
endif
if (product(totalShape) /= 0) then

View File

@ -65,8 +65,8 @@ end subroutine IO_init
function IO_readlines(fileName) result(fileContent)
character(len=*), intent(in) :: fileName
character(len=pStringLen), dimension(:), allocatable :: fileContent !< file content, separated per lines
character(len=pStringLen) :: line
character(len=:), allocatable :: rawData
integer :: &
@ -75,6 +75,7 @@ function IO_readlines(fileName) result(fileContent)
l
logical :: warned
rawData = IO_read(fileName)
!--------------------------------------------------------------------------------------------------
@ -112,16 +113,21 @@ end function IO_readlines
!--------------------------------------------------------------------------------------------------
!> @brief Read whole file.
!> @details ensures that the string ends with a new line (expected UNIX behavior)
!> @details ensures that the string ends with a new line (expected UNIX behavior) and rejects
! windows (CRLF) line endings
!--------------------------------------------------------------------------------------------------
function IO_read(fileName) result(fileContent)
character(len=*), intent(in) :: fileName
character(len=:), allocatable :: fileContent
integer :: &
fileLength, &
fileUnit, &
myStat
myStat, &
firstEOL
character, parameter :: CR = achar(13)
inquire(file = fileName, size=fileLength)
open(newunit=fileUnit, file=fileName, access='stream',&
@ -137,8 +143,12 @@ function IO_read(fileName) result(fileContent)
if(myStat /= 0) call IO_error(102,ext_msg=trim(fileName))
close(fileUnit)
if(fileContent(fileLength:fileLength) /= IO_EOL) fileContent = fileContent//IO_EOL ! ensure EOL@EOF
firstEOL = index(fileContent,IO_EOL)
if(scan(fileContent(firstEOL:firstEOL),CR) /= 0) call IO_error(115)
end function IO_read
@ -151,6 +161,7 @@ logical pure function IO_isBlank(string)
integer :: posNonBlank
posNonBlank = verify(string,IO_WHITESPACE)
IO_isBlank = posNonBlank == 0 .or. posNonBlank == scan(string,IO_COMMENT)
@ -170,6 +181,7 @@ pure function IO_stringPos(string)
integer :: left, right
allocate(IO_stringPos(1), source=0)
right = 0
@ -249,6 +261,7 @@ pure function IO_lc(string)
integer :: i,n
do i=1,len(string)
n = index(UPPER,string(i:i))
if(n/=0) then
@ -271,6 +284,7 @@ function IO_rmComment(line)
character(len=:), allocatable :: IO_rmComment
integer :: split
split = index(line,IO_COMMENT)
if (split == 0) then
@ -292,6 +306,7 @@ integer function IO_stringAsInt(string)
integer :: readStatus
character(len=*), parameter :: VALIDCHARS = '0123456789+- '
valid: if (verify(string,VALIDCHARS) == 0) then
read(string,*,iostat=readStatus) IO_stringAsInt
if (readStatus /= 0) call IO_error(111,ext_msg=string)
@ -313,6 +328,7 @@ real(pReal) function IO_stringAsFloat(string)
integer :: readStatus
character(len=*), parameter :: VALIDCHARS = '0123456789eE.+- '
valid: if (verify(string,VALIDCHARS) == 0) then
read(string,*,iostat=readStatus) IO_stringAsFloat
if (readStatus /= 0) call IO_error(112,ext_msg=string)
@ -331,6 +347,7 @@ logical function IO_stringAsBool(string)
character(len=*), intent(in) :: string !< string for conversion to int value
if (trim(adjustl(string)) == 'True' .or. trim(adjustl(string)) == 'true') then
IO_stringAsBool = .true.
elseif (trim(adjustl(string)) == 'False' .or. trim(adjustl(string)) == 'false') then
@ -356,6 +373,7 @@ subroutine IO_error(error_ID,el,ip,g,instance,ext_msg)
character(len=:), allocatable :: msg
character(len=pStringLen) :: formatString
select case (error_ID)
!--------------------------------------------------------------------------------------------------
@ -382,6 +400,9 @@ subroutine IO_error(error_ID,el,ip,g,instance,ext_msg)
msg = 'invalid character for logical:'
case (114)
msg = 'cannot decode base64 string:'
case (115)
msg = 'found CR. Windows file endings (CRLF) are not supported.'
!--------------------------------------------------------------------------------------------------
! lattice error messages

View File

@ -72,7 +72,7 @@ module YAML_types
getKey => tNode_getKey_byIndex
procedure :: &
contains => tNode_contains
generic :: &
get => tNode_get_byIndex, &
tNode_get_byKey
@ -157,7 +157,7 @@ module YAML_types
emptyDict
type(tList), target, public :: &
emptyList
abstract interface
recursive function asFormattedString(self,indent)
@ -179,7 +179,7 @@ module YAML_types
public :: &
YAML_types_init, &
output_asStrings, & !ToDo: Hack for GNU. Remove later
output_asStrings, & !ToDo: Hack for GNU. Remove later
assignment(=)
contains
@ -207,11 +207,11 @@ subroutine selfTest
select type(s1)
class is(tScalar)
s1 = '1'
if(s1%asInt() /= 1) error stop 'tScalar_asInt'
if(dNeq(s1%asFloat(),1.0_pReal)) error stop 'tScalar_asFloat'
if (s1%asInt() /= 1) error stop 'tScalar_asInt'
if (dNeq(s1%asFloat(),1.0_pReal)) error stop 'tScalar_asFloat'
s1 = 'true'
if(.not. s1%asBool()) error stop 'tScalar_asBool'
if(s1%asString() /= 'true') error stop 'tScalar_asString'
if (.not. s1%asBool()) error stop 'tScalar_asBool'
if (s1%asString() /= 'true') error stop 'tScalar_asString'
end select
block
@ -232,18 +232,18 @@ subroutine selfTest
call l1%append(s1)
call l1%append(s2)
n => l1
if(any(l1%asInts() /= [2,3])) error stop 'tList_asInts'
if(any(dNeq(l1%asFloats(),[2.0_pReal,3.0_pReal]))) error stop 'tList_asFloats'
if(n%get_asInt(1) /= 2) error stop 'byIndex_asInt'
if(dNeq(n%get_asFloat(2),3.0_pReal)) error stop 'byIndex_asFloat'
if (any(l1%asInts() /= [2,3])) error stop 'tList_asInts'
if (any(dNeq(l1%asFloats(),[2.0_pReal,3.0_pReal]))) error stop 'tList_asFloats'
if (n%get_asInt(1) /= 2) error stop 'byIndex_asInt'
if (dNeq(n%get_asFloat(2),3.0_pReal)) error stop 'byIndex_asFloat'
endselect
allocate(tList::l2)
select type(l2)
class is(tList)
call l2%append(l1)
if(any(l2%get_asInts(1) /= [2,3])) error stop 'byIndex_asInts'
if(any(dNeq(l2%get_asFloats(1),[2.0_pReal,3.0_pReal]))) error stop 'byIndex_asFloats'
if (any(l2%get_asInts(1) /= [2,3])) error stop 'byIndex_asInts'
if (any(dNeq(l2%get_asFloats(1),[2.0_pReal,3.0_pReal]))) error stop 'byIndex_asFloats'
n => l2
end select
deallocate(n)
@ -265,10 +265,10 @@ subroutine selfTest
call l1%append(s2)
n => l1
if(any(l1%asBools() .neqv. [.true., .false.])) error stop 'tList_asBools'
if(any(l1%asStrings() /= ['true ','False'])) error stop 'tList_asStrings'
if(n%get_asBool(2)) error stop 'byIndex_asBool'
if(n%get_asString(1) /= 'true') error stop 'byIndex_asString'
if (any(l1%asBools() .neqv. [.true., .false.])) error stop 'tList_asBools'
if (any(l1%asStrings() /= ['true ','False'])) error stop 'tList_asStrings'
if (n%get_asBool(2)) error stop 'byIndex_asBool'
if (n%get_asString(1) /= 'true') error stop 'byIndex_asString'
end block
end subroutine selfTest
@ -418,7 +418,7 @@ function tNode_get_byIndex(self,i) result(node)
integer :: j
self_ => self%asList()
if(i < 1 .or. i > self_%length) call IO_error(150,ext_msg='tNode_get_byIndex')
if (i < 1 .or. i > self_%length) call IO_error(150,ext_msg='tNode_get_byIndex')
j = 1
item => self_%first
@ -599,7 +599,7 @@ function tNode_getKey_byIndex(self,i) result(key)
dict => self%asDict()
item => dict%first
do j = 1, dict%length
if(j == i) then
if (j == i) then
key = item%key
exit
else
@ -613,7 +613,7 @@ end function tNode_getKey_byIndex
!-------------------------------------------------------------------------------------------------
!> @brief Checks if a given key/item is present in the dict/list
!-------------------------------------------------------------------------------------------------
function tNode_contains(self,k) result(exists)
function tNode_contains(self,k) result(exists)
class(tNode), intent(in), target :: self
character(len=*), intent(in) :: k
@ -624,18 +624,18 @@ function tNode_contains(self,k) result(exists)
type(tDict), pointer :: dict
exists = .false.
if(self%isDict()) then
if (self%isDict()) then
dict => self%asDict()
do j=1, dict%length
if(dict%getKey(j) == k) then
if (dict%getKey(j) == k) then
exists = .true.
return
endif
enddo
elseif(self%isList()) then
elseif (self%isList()) then
list => self%asList()
do j =1, list%length
if(list%get_asString(j) == k) then
do j=1, list%length
if (list%get_asString(j) == k) then
exists = .true.
return
endif
@ -663,8 +663,8 @@ function tNode_get_byKey(self,k,defaultVal) result(node)
logical :: found
found = present(defaultVal)
if(found) node => defaultVal
if (found) node => defaultVal
self_ => self%asDict()
j = 1
@ -677,11 +677,11 @@ function tNode_get_byKey(self,k,defaultVal) result(node)
item => item%next
j = j + 1
enddo
if (.not. found) then
call IO_error(143,ext_msg=k)
else
if(associated(item)) node => item%node
if (associated(item)) node => item%node
endif
end function tNode_get_byKey
@ -700,11 +700,11 @@ function tNode_get_byKey_asFloat(self,k,defaultVal) result(nodeAsFloat)
class(tNode), pointer :: node
type(tScalar), pointer :: scalar
if(self%contains(k)) then
if (self%contains(k)) then
node => self%get(k)
scalar => node%asScalar()
nodeAsFloat = scalar%asFloat()
elseif(present(defaultVal)) then
elseif (present(defaultVal)) then
nodeAsFloat = defaultVal
else
call IO_error(143,ext_msg=k)
@ -726,11 +726,11 @@ function tNode_get_byKey_asInt(self,k,defaultVal) result(nodeAsInt)
class(tNode), pointer :: node
type(tScalar), pointer :: scalar
if(self%contains(k)) then
if (self%contains(k)) then
node => self%get(k)
scalar => node%asScalar()
nodeAsInt = scalar%asInt()
elseif(present(defaultVal)) then
elseif (present(defaultVal)) then
nodeAsInt = defaultVal
else
call IO_error(143,ext_msg=k)
@ -752,11 +752,11 @@ function tNode_get_byKey_asBool(self,k,defaultVal) result(nodeAsBool)
class(tNode), pointer :: node
type(tScalar), pointer :: scalar
if(self%contains(k)) then
if (self%contains(k)) then
node => self%get(k)
scalar => node%asScalar()
nodeAsBool = scalar%asBool()
elseif(present(defaultVal)) then
elseif (present(defaultVal)) then
nodeAsBool = defaultVal
else
call IO_error(143,ext_msg=k)
@ -778,11 +778,11 @@ function tNode_get_byKey_asString(self,k,defaultVal) result(nodeAsString)
class(tNode), pointer :: node
type(tScalar), pointer :: scalar
if(self%contains(k)) then
if (self%contains(k)) then
node => self%get(k)
scalar => node%asScalar()
nodeAsString = scalar%asString()
elseif(present(defaultVal)) then
elseif (present(defaultVal)) then
nodeAsString = defaultVal
else
call IO_error(143,ext_msg=k)
@ -806,18 +806,18 @@ function tNode_get_byKey_asFloats(self,k,defaultVal,requiredSize) result(nodeAsF
class(tNode), pointer :: node
type(tList), pointer :: list
if(self%contains(k)) then
if (self%contains(k)) then
node => self%get(k)
list => node%asList()
nodeAsFloats = list%asFloats()
elseif(present(defaultVal)) then
elseif (present(defaultVal)) then
nodeAsFloats = defaultVal
else
call IO_error(143,ext_msg=k)
endif
if(present(requiredSize)) then
if(requiredSize /= size(nodeAsFloats)) call IO_error(146,ext_msg=k)
if (present(requiredSize)) then
if (requiredSize /= size(nodeAsFloats)) call IO_error(146,ext_msg=k)
endif
end function tNode_get_byKey_asFloats
@ -837,18 +837,18 @@ function tNode_get_byKey_asInts(self,k,defaultVal,requiredSize) result(nodeAsInt
class(tNode), pointer :: node
type(tList), pointer :: list
if(self%contains(k)) then
if (self%contains(k)) then
node => self%get(k)
list => node%asList()
nodeAsInts = list%asInts()
elseif(present(defaultVal)) then
elseif (present(defaultVal)) then
nodeAsInts = defaultVal
else
call IO_error(143,ext_msg=k)
endif
if(present(requiredSize)) then
if(requiredSize /= size(nodeAsInts)) call IO_error(146,ext_msg=k)
if (present(requiredSize)) then
if (requiredSize /= size(nodeAsInts)) call IO_error(146,ext_msg=k)
endif
end function tNode_get_byKey_asInts
@ -867,11 +867,11 @@ function tNode_get_byKey_asBools(self,k,defaultVal) result(nodeAsBools)
class(tNode), pointer :: node
type(tList), pointer :: list
if(self%contains(k)) then
if (self%contains(k)) then
node => self%get(k)
list => node%asList()
nodeAsBools = list%asBools()
elseif(present(defaultVal)) then
elseif (present(defaultVal)) then
nodeAsBools = defaultVal
else
call IO_error(143,ext_msg=k)
@ -893,11 +893,11 @@ function tNode_get_byKey_asStrings(self,k,defaultVal) result(nodeAsStrings)
class(tNode), pointer :: node
type(tList), pointer :: list
if(self%contains(k)) then
if (self%contains(k)) then
node => self%get(k)
list => node%asList()
nodeAsStrings = list%asStrings()
elseif(present(defaultVal)) then
elseif (present(defaultVal)) then
nodeAsStrings = defaultVal
else
call IO_error(143,ext_msg=k)
@ -925,7 +925,7 @@ function output_asStrings(self) result(output) !ToDo: SR: Rem
end function output_asStrings
!--------------------------------------------------------------------------------------------------
!> @brief Returns the index of a key in a dictionary
@ -944,7 +944,7 @@ function tNode_get_byKey_asIndex(self,key) result(keyIndex)
item => dict%first
keyIndex = -1
do i = 1, dict%length
if(key == item%key) then
if (key == item%key) then
keyIndex = i
exit
else
@ -952,9 +952,9 @@ function tNode_get_byKey_asIndex(self,key) result(keyIndex)
endif
enddo
if(keyIndex == -1) call IO_error(140,ext_msg=key)
if (keyIndex == -1) call IO_error(140,ext_msg=key)
end function tNode_get_byKey_asIndex
@ -985,7 +985,7 @@ recursive function tList_asFormattedString(self,indent) result(str)
integer :: i, indent_
str = ''
if(present(indent)) then
if (present(indent)) then
indent_ = indent
else
indent_ = 0
@ -993,7 +993,7 @@ recursive function tList_asFormattedString(self,indent) result(str)
item => self%first
do i = 1, self%length
if(i /= 1) str = str//repeat(' ',indent_)
if (i /= 1) str = str//repeat(' ',indent_)
str = str//'- '//item%node%asFormattedString(indent_+2)
item => item%next
end do
@ -1014,7 +1014,7 @@ recursive function tDict_asFormattedString(self,indent) result(str)
integer :: i, indent_
str = ''
if(present(indent)) then
if (present(indent)) then
indent_ = indent
else
indent_ = 0
@ -1022,7 +1022,7 @@ recursive function tDict_asFormattedString(self,indent) result(str)
item => self%first
do i = 1, self%length
if(i /= 1) str = str//repeat(' ',indent_)
if (i /= 1) str = str//repeat(' ',indent_)
select type(node_1 =>item%node)
class is(tScalar)
str = str//trim(item%key)//': '//item%node%asFormattedString(indent_+len_trim(item%key)+2)
@ -1270,7 +1270,7 @@ recursive subroutine tItem_finalize(self)
type(tItem),intent(inout) :: self
deallocate(self%node)
if(associated(self%next)) deallocate(self%next)
if (associated(self%next)) deallocate(self%next)
end subroutine tItem_finalize

View File

@ -7,7 +7,6 @@
#include "IO.f90"
#include "YAML_types.f90"
#include "YAML_parse.f90"
#include "future.f90"
#include "config.f90"
#include "LAPACK_interface.f90"
#include "math.f90"
@ -17,38 +16,36 @@
#include "results.f90"
#include "geometry_plastic_nonlocal.f90"
#include "discretization.f90"
#ifdef Marc4DAMASK
#include "marc/discretization_marc.f90"
#endif
#include "material.f90"
#include "lattice.f90"
#include "constitutive.f90"
#include "constitutive_mech.f90"
#include "constitutive_plastic_none.f90"
#include "constitutive_plastic_isotropic.f90"
#include "constitutive_plastic_phenopowerlaw.f90"
#include "constitutive_plastic_kinehardening.f90"
#include "constitutive_plastic_dislotwin.f90"
#include "constitutive_plastic_disloTungsten.f90"
#include "constitutive_plastic_nonlocal.f90"
#include "constitutive_thermal.f90"
#include "source_thermal_dissipation.f90"
#include "source_thermal_externalheat.f90"
#include "kinematics_thermal_expansion.f90"
#include "constitutive_damage.f90"
#include "source_damage_isoBrittle.f90"
#include "source_damage_isoDuctile.f90"
#include "source_damage_anisoBrittle.f90"
#include "source_damage_anisoDuctile.f90"
#include "kinematics_cleavage_opening.f90"
#include "kinematics_slipplane_opening.f90"
#include "thermal_isothermal.f90"
#include "thermal_conduction.f90"
#include "damage_none.f90"
#include "damage_nonlocal.f90"
#include "phase.f90"
#include "phase_mechanical.f90"
#include "phase_mechanical_plastic.f90"
#include "phase_mechanical_plastic_none.f90"
#include "phase_mechanical_plastic_isotropic.f90"
#include "phase_mechanical_plastic_phenopowerlaw.f90"
#include "phase_mechanical_plastic_kinehardening.f90"
#include "phase_mechanical_plastic_dislotwin.f90"
#include "phase_mechanical_plastic_dislotungsten.f90"
#include "phase_mechanical_plastic_nonlocal.f90"
#include "phase_mechanical_eigen.f90"
#include "phase_mechanical_eigen_cleavageopening.f90"
#include "phase_mechanical_eigen_slipplaneopening.f90"
#include "phase_mechanical_eigen_thermalexpansion.f90"
#include "phase_thermal.f90"
#include "phase_thermal_dissipation.f90"
#include "phase_thermal_externalheat.f90"
#include "phase_damage.f90"
#include "phase_damage_isobrittle.f90"
#include "phase_damage_isoductile.f90"
#include "phase_damage_anisobrittle.f90"
#include "phase_damage_anisoductile.f90"
#include "homogenization.f90"
#include "homogenization_mech.f90"
#include "homogenization_mech_none.f90"
#include "homogenization_mech_isostrain.f90"
#include "homogenization_mech_RGC.f90"
#include "homogenization_mechanical.f90"
#include "homogenization_mechanical_pass.f90"
#include "homogenization_mechanical_isostrain.f90"
#include "homogenization_mechanical_RGC.f90"
#include "homogenization_thermal.f90"
#include "homogenization_damage.f90"
#include "CPFEM.f90"

View File

@ -5,16 +5,10 @@
!! precedence over material.yaml.
!--------------------------------------------------------------------------------------------------
module config
use prec
use DAMASK_interface
use IO
use YAML_parse
use YAML_types
#ifdef PETSc
#include <petsc/finclude/petscsys.h>
use petscsys
#endif
implicit none
private
@ -50,17 +44,12 @@ end subroutine config_init
subroutine parse_material
logical :: fileExists
character(len=:), allocatable :: fname
fname = getSolverJobName()//'.yaml'
inquire(file=fname,exist=fileExists)
if(.not. fileExists) then
fname = 'material.yaml'
inquire(file=fname,exist=fileExists)
if(.not. fileExists) call IO_error(100,ext_msg=fname)
endif
print*, 'reading '//fname; flush(IO_STDOUT)
config_material => YAML_parse_file(fname)
inquire(file='material.yaml',exist=fileExists)
if(.not. fileExists) call IO_error(100,ext_msg='material.yaml')
print*, 'reading material.yaml'; flush(IO_STDOUT)
config_material => YAML_parse_file('material.yaml')
end subroutine parse_material
@ -72,6 +61,7 @@ subroutine parse_numerics
logical :: fexist
config_numerics => emptyDict
inquire(file='numerics.yaml', exist=fexist)
if (fexist) then
@ -89,6 +79,7 @@ subroutine parse_debug
logical :: fexist
config_debug => emptyDict
inquire(file='debug.yaml', exist=fexist)
fileExists: if (fexist) then

File diff suppressed because it is too large Load Diff

View File

@ -1,253 +0,0 @@
!----------------------------------------------------------------------------------------------------
!> @brief internal microstructure state for all damage sources and kinematics constitutive models
!----------------------------------------------------------------------------------------------------
submodule(constitutive) constitutive_damage
interface
module function source_damage_anisoBrittle_init(source_length) result(mySources)
integer, intent(in) :: source_length
logical, dimension(:,:), allocatable :: mySources
end function source_damage_anisoBrittle_init
module function source_damage_anisoDuctile_init(source_length) result(mySources)
integer, intent(in) :: source_length
logical, dimension(:,:), allocatable :: mySources
end function source_damage_anisoDuctile_init
module function source_damage_isoBrittle_init(source_length) result(mySources)
integer, intent(in) :: source_length
logical, dimension(:,:), allocatable :: mySources
end function source_damage_isoBrittle_init
module function source_damage_isoDuctile_init(source_length) result(mySources)
integer, intent(in) :: source_length
logical, dimension(:,:), allocatable :: mySources
end function source_damage_isoDuctile_init
module function kinematics_cleavage_opening_init(kinematics_length) result(myKinematics)
integer, intent(in) :: kinematics_length
logical, dimension(:,:), allocatable :: myKinematics
end function kinematics_cleavage_opening_init
module function kinematics_slipplane_opening_init(kinematics_length) result(myKinematics)
integer, intent(in) :: kinematics_length
logical, dimension(:,:), allocatable :: myKinematics
end function kinematics_slipplane_opening_init
module subroutine source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, phase, constituent)
integer, intent(in) :: &
phase, & !< phase ID of element
constituent !< position of element within its phase instance
real(pReal), intent(in) :: &
phi !< damage parameter
real(pReal), intent(out) :: &
localphiDot, &
dLocalphiDot_dPhi
end subroutine source_damage_anisoBrittle_getRateAndItsTangent
module subroutine source_damage_anisoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, phase, constituent)
integer, intent(in) :: &
phase, & !< phase ID of element
constituent !< position of element within its phase instance
real(pReal), intent(in) :: &
phi !< damage parameter
real(pReal), intent(out) :: &
localphiDot, &
dLocalphiDot_dPhi
end subroutine source_damage_anisoDuctile_getRateAndItsTangent
module subroutine source_damage_isoBrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, phase, constituent)
integer, intent(in) :: &
phase, & !< phase ID of element
constituent !< position of element within its phase instance
real(pReal), intent(in) :: &
phi !< damage parameter
real(pReal), intent(out) :: &
localphiDot, &
dLocalphiDot_dPhi
end subroutine source_damage_isoBrittle_getRateAndItsTangent
module subroutine source_damage_isoDuctile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, phase, constituent)
integer, intent(in) :: &
phase, & !< phase ID of element
constituent !< position of element within its phase instance
real(pReal), intent(in) :: &
phi !< damage parameter
real(pReal), intent(out) :: &
localphiDot, &
dLocalphiDot_dPhi
end subroutine source_damage_isoDuctile_getRateAndItsTangent
module subroutine source_damage_anisoBrittle_results(phase,group)
integer, intent(in) :: phase
character(len=*), intent(in) :: group
end subroutine source_damage_anisoBrittle_results
module subroutine source_damage_anisoDuctile_results(phase,group)
integer, intent(in) :: phase
character(len=*), intent(in) :: group
end subroutine source_damage_anisoDuctile_results
module subroutine source_damage_isoBrittle_results(phase,group)
integer, intent(in) :: phase
character(len=*), intent(in) :: group
end subroutine source_damage_isoBrittle_results
module subroutine source_damage_isoDuctile_results(phase,group)
integer, intent(in) :: phase
character(len=*), intent(in) :: group
end subroutine source_damage_isoDuctile_results
end interface
contains
!----------------------------------------------------------------------------------------------
!< @brief initialize damage sources and kinematics mechanism
!----------------------------------------------------------------------------------------------
module subroutine damage_init
integer :: &
ph !< counter in phase loop
class(tNode), pointer :: &
phases, &
phase, &
sources, &
kinematics
phases => config_material%get('phase')
allocate(sourceState (phases%length))
allocate(phase_Nsources(phases%length),source = 0) ! same for kinematics
do ph = 1,phases%length
phase => phases%get(ph)
sources => phase%get('source',defaultVal=emptyList)
phase_Nsources(ph) = sources%length
allocate(sourceState(ph)%p(phase_Nsources(ph)))
enddo
allocate(phase_source(maxval(phase_Nsources),phases%length), source = SOURCE_undefined_ID)
! initialize source mechanisms
if(maxval(phase_Nsources) /= 0) then
where(source_damage_isoBrittle_init (maxval(phase_Nsources))) phase_source = SOURCE_damage_isoBrittle_ID
where(source_damage_isoDuctile_init (maxval(phase_Nsources))) phase_source = SOURCE_damage_isoDuctile_ID
where(source_damage_anisoBrittle_init (maxval(phase_Nsources))) phase_source = SOURCE_damage_anisoBrittle_ID
where(source_damage_anisoDuctile_init (maxval(phase_Nsources))) phase_source = SOURCE_damage_anisoDuctile_ID
endif
!--------------------------------------------------------------------------------------------------
! initialize kinematic mechanisms
allocate(phase_Nkinematics(phases%length),source = 0)
do ph = 1,phases%length
phase => phases%get(ph)
kinematics => phase%get('kinematics',defaultVal=emptyList)
phase_Nkinematics(ph) = kinematics%length
enddo
allocate(phase_kinematics(maxval(phase_Nkinematics),phases%length), source = KINEMATICS_undefined_ID)
if(maxval(phase_Nkinematics) /= 0) then
where(kinematics_cleavage_opening_init(maxval(phase_Nkinematics))) phase_kinematics = KINEMATICS_cleavage_opening_ID
where(kinematics_slipplane_opening_init(maxval(phase_Nkinematics))) phase_kinematics = KINEMATICS_slipplane_opening_ID
endif
end subroutine damage_init
!----------------------------------------------------------------------------------------------
!< @brief returns local part of nonlocal damage driving force
!----------------------------------------------------------------------------------------------
module subroutine constitutive_damage_getRateAndItsTangents(phiDot, dPhiDot_dPhi, phi, ip, el)
integer, intent(in) :: &
ip, & !< integration point number
el !< element number
real(pReal), intent(in) :: &
phi !< damage parameter
real(pReal), intent(inout) :: &
phiDot, &
dPhiDot_dPhi
real(pReal) :: &
localphiDot, &
dLocalphiDot_dPhi
integer :: &
phase, &
grain, &
source, &
constituent
phiDot = 0.0_pReal
dPhiDot_dPhi = 0.0_pReal
do grain = 1, homogenization_Nconstituents(material_homogenizationAt(el))
phase = material_phaseAt(grain,el)
constituent = material_phasememberAt(grain,ip,el)
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, phase, constituent)
case (SOURCE_damage_isoDuctile_ID)
call source_damage_isoductile_getRateAndItsTangent (localphiDot, dLocalphiDot_dPhi, phi, phase, constituent)
case (SOURCE_damage_anisoBrittle_ID)
call source_damage_anisobrittle_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, phase, constituent)
case (SOURCE_damage_anisoDuctile_ID)
call source_damage_anisoductile_getRateAndItsTangent(localphiDot, dLocalphiDot_dPhi, phi, phase, constituent)
case default
localphiDot = 0.0_pReal
dLocalphiDot_dPhi = 0.0_pReal
end select
phiDot = phiDot + localphiDot
dPhiDot_dPhi = dPhiDot_dPhi + dLocalphiDot_dPhi
enddo
enddo
end subroutine constitutive_damage_getRateAndItsTangents
!----------------------------------------------------------------------------------------------
!< @brief writes damage sources results to HDF5 output file
!----------------------------------------------------------------------------------------------
module subroutine damage_results(group,ph)
character(len=*), intent(in) :: group
integer, intent(in) :: ph
integer :: so
sourceLoop: do so = 1, phase_Nsources(ph)
if (phase_source(so,ph) /= SOURCE_UNDEFINED_ID) &
call results_closeGroup(results_addGroup(group//'sources/')) ! should be 'damage'
sourceType: select case (phase_source(so,ph))
case (SOURCE_damage_anisoBrittle_ID) sourceType
call source_damage_anisoBrittle_results(ph,group//'sources/')
case (SOURCE_damage_anisoDuctile_ID) sourceType
call source_damage_anisoDuctile_results(ph,group//'sources/')
case (SOURCE_damage_isoBrittle_ID) sourceType
call source_damage_isoBrittle_results(ph,group//'sources/')
case (SOURCE_damage_isoDuctile_ID) sourceType
call source_damage_isoDuctile_results(ph,group//'sources/')
end select sourceType
enddo SourceLoop
end subroutine damage_results
end submodule constitutive_damage

View File

@ -1,125 +0,0 @@
!----------------------------------------------------------------------------------------------------
!> @brief internal microstructure state for all thermal sources and kinematics constitutive models
!----------------------------------------------------------------------------------------------------
submodule(constitutive) constitutive_thermal
interface
module function source_thermal_dissipation_init(source_length) result(mySources)
integer, intent(in) :: source_length
logical, dimension(:,:), allocatable :: mySources
end function source_thermal_dissipation_init
module function source_thermal_externalheat_init(source_length) result(mySources)
integer, intent(in) :: source_length
logical, dimension(:,:), allocatable :: mySources
end function source_thermal_externalheat_init
module function kinematics_thermal_expansion_init(kinematics_length) result(myKinematics)
integer, intent(in) :: kinematics_length
logical, dimension(:,:), allocatable :: myKinematics
end function kinematics_thermal_expansion_init
module subroutine source_thermal_dissipation_getRateAndItsTangent(TDot, dTDot_dT, Tstar, Lp, phase)
integer, intent(in) :: &
phase !< phase ID of element
real(pReal), intent(in), dimension(3,3) :: &
Tstar !< 2nd Piola Kirchhoff stress tensor for a given element
real(pReal), intent(in), dimension(3,3) :: &
Lp !< plastic velocuty gradient for a given element
real(pReal), intent(out) :: &
TDot, &
dTDot_dT
end subroutine source_thermal_dissipation_getRateAndItsTangent
module subroutine source_thermal_externalheat_getRateAndItsTangent(TDot, dTDot_dT, phase, of)
integer, intent(in) :: &
phase, &
of
real(pReal), intent(out) :: &
TDot, &
dTDot_dT
end subroutine source_thermal_externalheat_getRateAndItsTangent
end interface
contains
!----------------------------------------------------------------------------------------------
!< @brief initializes thermal sources and kinematics mechanism
!----------------------------------------------------------------------------------------------
module subroutine thermal_init
! initialize source mechanisms
if(maxval(phase_Nsources) /= 0) then
where(source_thermal_dissipation_init (maxval(phase_Nsources))) phase_source = SOURCE_thermal_dissipation_ID
where(source_thermal_externalheat_init(maxval(phase_Nsources))) phase_source = SOURCE_thermal_externalheat_ID
endif
!--------------------------------------------------------------------------------------------------
!initialize kinematic mechanisms
if(maxval(phase_Nkinematics) /= 0) where(kinematics_thermal_expansion_init(maxval(phase_Nkinematics))) &
phase_kinematics = KINEMATICS_thermal_expansion_ID
end subroutine thermal_init
!----------------------------------------------------------------------------------------------
!< @brief calculates thermal dissipation rate
!----------------------------------------------------------------------------------------------
module subroutine constitutive_thermal_getRateAndItsTangents(TDot, dTDot_dT, T, S, Lp, ip, el)
integer, intent(in) :: &
ip, & !< integration point number
el !< element number
real(pReal), intent(in) :: &
T
real(pReal), intent(in), dimension(:,:,:,:,:) :: &
S, & !< current 2nd Piola Kirchhoff stress
Lp !< plastic velocity gradient
real(pReal), intent(inout) :: &
TDot, &
dTDot_dT
real(pReal) :: &
my_Tdot, &
my_dTdot_dT
integer :: &
phase, &
homog, &
instance, &
grain, &
source, &
constituent
homog = material_homogenizationAt(el)
instance = thermal_typeInstance(homog)
do grain = 1, homogenization_Nconstituents(homog)
phase = material_phaseAt(grain,el)
constituent = material_phasememberAt(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, &
S(1:3,1:3,grain,ip,el), &
Lp(1:3,1:3,grain,ip,el), &
phase)
case (SOURCE_thermal_externalheat_ID)
call source_thermal_externalheat_getRateAndItsTangent(my_Tdot, my_dTdot_dT, &
phase, constituent)
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
end subroutine constitutive_thermal_getRateAndItsTangents
end submodule constitutive_thermal

View File

@ -1,39 +0,0 @@
!--------------------------------------------------------------------------------------------------
!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH
!> @brief material subroutine for constant damage field
!--------------------------------------------------------------------------------------------------
module damage_none
use prec
use config
use material
implicit none
public
contains
!--------------------------------------------------------------------------------------------------
!> @brief allocates all neccessary fields, reads information from material configuration file
!--------------------------------------------------------------------------------------------------
subroutine damage_none_init
integer :: h,Nmaterialpoints
print'(/,a)', ' <<<+- damage_none init -+>>>'; flush(6)
do h = 1, size(material_name_homogenization)
if (damage_type(h) /= DAMAGE_NONE_ID) cycle
Nmaterialpoints = count(material_homogenizationAt == h)
damageState(h)%sizeState = 0
allocate(damageState(h)%state0 (0,Nmaterialpoints))
allocate(damageState(h)%subState0(0,Nmaterialpoints))
allocate(damageState(h)%state (0,Nmaterialpoints))
allocate (damage(h)%p(Nmaterialpoints), source=1.0_pReal)
enddo
end subroutine damage_none_init
end module damage_none

View File

@ -1,208 +0,0 @@
!--------------------------------------------------------------------------------------------------
!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH
!> @brief material subroutine for non-locally evolving damage field
!--------------------------------------------------------------------------------------------------
module damage_nonlocal
use prec
use material
use config
use YAML_types
use lattice
use constitutive
use results
implicit none
private
type :: tParameters
character(len=pStringLen), allocatable, dimension(:) :: &
output
end type tParameters
type, private :: tNumerics
real(pReal) :: &
charLength !< characteristic length scale for gradient problems
end type tNumerics
type(tparameters), dimension(:), allocatable :: &
param
type(tNumerics), private :: &
num
public :: &
damage_nonlocal_init, &
damage_nonlocal_getSourceAndItsTangent, &
damage_nonlocal_getDiffusion, &
damage_nonlocal_getMobility, &
damage_nonlocal_putNonLocalDamage, &
damage_nonlocal_results
contains
!--------------------------------------------------------------------------------------------------
!> @brief module initialization
!> @details reads in material parameters, allocates arrays, and does sanity checks
!--------------------------------------------------------------------------------------------------
subroutine damage_nonlocal_init
integer :: Ninstances,Nmaterialpoints,h
class(tNode), pointer :: &
num_generic, &
material_homogenization, &
homog, &
homogDamage
print'(/,a)', ' <<<+- damage_nonlocal init -+>>>'; flush(6)
!------------------------------------------------------------------------------------
! read numerics parameter
num_generic => config_numerics%get('generic',defaultVal= emptyDict)
num%charLength = num_generic%get_asFloat('charLength',defaultVal=1.0_pReal)
Ninstances = count(damage_type == DAMAGE_nonlocal_ID)
allocate(param(Ninstances))
material_homogenization => config_material%get('homogenization')
do h = 1, material_homogenization%length
if (damage_type(h) /= DAMAGE_NONLOCAL_ID) cycle
homog => material_homogenization%get(h)
homogDamage => homog%get('damage')
associate(prm => param(damage_typeInstance(h)))
#if defined (__GFORTRAN__)
prm%output = output_asStrings(homogDamage)
#else
prm%output = homogDamage%get_asStrings('output',defaultVal=emptyStringArray)
#endif
Nmaterialpoints = count(material_homogenizationAt == h)
damageState(h)%sizeState = 1
allocate(damageState(h)%state0 (1,Nmaterialpoints), source=1.0_pReal)
allocate(damageState(h)%subState0(1,Nmaterialpoints), source=1.0_pReal)
allocate(damageState(h)%state (1,Nmaterialpoints), source=1.0_pReal)
damage(h)%p => damageState(h)%state(1,:)
end associate
enddo
end subroutine damage_nonlocal_init
!--------------------------------------------------------------------------------------------------
!> @brief calculates homogenized damage driving forces
!--------------------------------------------------------------------------------------------------
subroutine damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ip, el)
integer, intent(in) :: &
ip, & !< integration point number
el !< element number
real(pReal), intent(in) :: &
phi
real(pReal) :: &
phiDot, dPhiDot_dPhi
phiDot = 0.0_pReal
dPhiDot_dPhi = 0.0_pReal
call constitutive_damage_getRateAndItsTangents(phiDot, dPhiDot_dPhi, phi, ip, el)
phiDot = phiDot/real(homogenization_Nconstituents(material_homogenizationAt(el)),pReal)
dPhiDot_dPhi = dPhiDot_dPhi/real(homogenization_Nconstituents(material_homogenizationAt(el)),pReal)
end subroutine damage_nonlocal_getSourceAndItsTangent
!--------------------------------------------------------------------------------------------------
!> @brief returns homogenized non local damage diffusion tensor in reference configuration
!--------------------------------------------------------------------------------------------------
function damage_nonlocal_getDiffusion(ip,el)
integer, intent(in) :: &
ip, & !< integration point number
el !< element number
real(pReal), dimension(3,3) :: &
damage_nonlocal_getDiffusion
integer :: &
homog, &
grain
homog = material_homogenizationAt(el)
damage_nonlocal_getDiffusion = 0.0_pReal
do grain = 1, homogenization_Nconstituents(homog)
damage_nonlocal_getDiffusion = damage_nonlocal_getDiffusion + &
crystallite_push33ToRef(grain,ip,el,lattice_D(1:3,1:3,material_phaseAt(grain,el)))
enddo
damage_nonlocal_getDiffusion = &
num%charLength**2*damage_nonlocal_getDiffusion/real(homogenization_Nconstituents(homog),pReal)
end function damage_nonlocal_getDiffusion
!--------------------------------------------------------------------------------------------------
!> @brief Returns homogenized nonlocal damage mobility
!--------------------------------------------------------------------------------------------------
real(pReal) function damage_nonlocal_getMobility(ip,el)
integer, intent(in) :: &
ip, & !< integration point number
el !< element number
integer :: &
co
damage_nonlocal_getMobility = 0.0_pReal
do co = 1, homogenization_Nconstituents(material_homogenizationAt(el))
damage_nonlocal_getMobility = damage_nonlocal_getMobility + lattice_M(material_phaseAt(co,el))
enddo
damage_nonlocal_getMobility = damage_nonlocal_getMobility/&
real(homogenization_Nconstituents(material_homogenizationAt(el)),pReal)
end function damage_nonlocal_getMobility
!--------------------------------------------------------------------------------------------------
!> @brief updated nonlocal damage field with solution from damage phase field PDE
!--------------------------------------------------------------------------------------------------
subroutine damage_nonlocal_putNonLocalDamage(phi,ip,el)
integer, intent(in) :: &
ip, & !< integration point number
el !< element number
real(pReal), intent(in) :: &
phi
integer :: &
homog, &
offset
homog = material_homogenizationAt(el)
offset = material_homogenizationMemberAt(ip,el)
damage(homog)%p(offset) = phi
end subroutine damage_nonlocal_putNonLocalDamage
!--------------------------------------------------------------------------------------------------
!> @brief writes results to HDF5 output file
!--------------------------------------------------------------------------------------------------
subroutine damage_nonlocal_results(homog,group)
integer, intent(in) :: homog
character(len=*), intent(in) :: group
integer :: o
associate(prm => param(damage_typeInstance(homog)))
outputsLoop: do o = 1,size(prm%output)
select case(prm%output(o))
case ('phi')
call results_writeDataset(group,damage(homog)%p,prm%output(o),&
'damage indicator','-')
end select
enddo outputsLoop
end associate
end subroutine damage_nonlocal_results
end module damage_nonlocal

View File

@ -686,7 +686,7 @@ module element
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 &
8,12,15,14, 4, 9,13,10 &
#if !defined(__GFORTRAN__)
],shape(CELL6))
#else

View File

@ -1,35 +0,0 @@
!--------------------------------------------------------------------------------------------------
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
!> @brief New fortran functions for compiler versions that do not support them
!--------------------------------------------------------------------------------------------------
module future
use prec
implicit none
public
contains
#if defined(__GFORTRAN__) && __GNUC__<9 || defined(__INTEL_COMPILER) && INTEL_COMPILER<1800
!--------------------------------------------------------------------------------------------------
!> @brief substitute for the findloc intrinsic (only for integer, dimension(:) at the moment)
!--------------------------------------------------------------------------------------------------
function findloc(a,v)
integer, intent(in), dimension(:) :: a
integer, intent(in) :: v
integer :: i,j
integer, allocatable, dimension(:) :: findloc
allocate(findloc(count(a==v)))
j = 1
do i = 1, size(a)
if (a(i)==v) then
findloc(j) = i
j = j + 1
endif
enddo
end function findloc
#endif
end module future

View File

@ -18,9 +18,9 @@ program DAMASK_grid
use CPFEM2
use material
use spectral_utilities
use grid_mech_spectral_basic
use grid_mech_spectral_polarisation
use grid_mech_FEM
use grid_mechanical_spectral_basic
use grid_mechanical_spectral_polarisation
use grid_mechanical_FEM
use grid_damage_spectral
use grid_thermal_spectral
use results
@ -36,10 +36,11 @@ program DAMASK_grid
integer :: N, & !< number of increments
f_out, & !< frequency of result writes
f_restart !< frequency of restart writes
logical :: drop_guessing !< do not follow trajectory of former loadcase
integer(kind(FIELD_UNDEFINED_ID)), allocatable :: ID(:)
logical :: estimate_rate !< follow trajectory of former loadcase
end type tLoadCase
integer(kind(FIELD_UNDEFINED_ID)), allocatable :: ID(:)
!--------------------------------------------------------------------------------------------------
! variables related to information from load case and geom file
real(pReal), dimension(9) :: temp_valueVector !< temporarily from loadcase file when reading in tensors (initialize to 0.0)
@ -53,6 +54,7 @@ program DAMASK_grid
integer, parameter :: &
subStepFactor = 2 !< for each substep, divide the last time increment by 2.0
real(pReal) :: &
T_0 = 300.0_pReal, &
time = 0.0_pReal, & !< elapsed time
time0 = 0.0_pReal, & !< begin of interval
timeinc = 1.0_pReal, & !< current time interval
@ -61,10 +63,12 @@ program DAMASK_grid
logical :: &
guess, & !< guess along former trajectory
stagIterate, &
cutBack = .false.
cutBack = .false.,&
signal
integer :: &
i, j, m, field, &
errorID = 0, &
ierr,&
cutBackLevel = 0, & !< cut back level \f$ t = \frac{t_{inc}}{2^l} \f$
stepFraction = 0, & !< fraction of current time interval
l = 0, & !< current load case
@ -76,30 +80,33 @@ program DAMASK_grid
maxCutBack, & !< max number of cut backs
stagItMax !< max number of field level staggered iterations
character(len=pStringLen) :: &
incInfo, &
loadcase_string
incInfo
type(tLoadCase), allocatable, dimension(:) :: loadCases !< array of all load cases
type(tSolutionState), allocatable, dimension(:) :: solres
procedure(grid_mech_spectral_basic_init), pointer :: &
mech_init
procedure(grid_mech_spectral_basic_forward), pointer :: &
mech_forward
procedure(grid_mech_spectral_basic_solution), pointer :: &
mech_solution
procedure(grid_mech_spectral_basic_updateCoords), pointer :: &
mech_updateCoords
procedure(grid_mech_spectral_basic_restartWrite), pointer :: &
mech_restartWrite
procedure(grid_mechanical_spectral_basic_init), pointer :: &
mechanical_init
procedure(grid_mechanical_spectral_basic_forward), pointer :: &
mechanical_forward
procedure(grid_mechanical_spectral_basic_solution), pointer :: &
mechanical_solution
procedure(grid_mechanical_spectral_basic_updateCoords), pointer :: &
mechanical_updateCoords
procedure(grid_mechanical_spectral_basic_restartWrite), pointer :: &
mechanical_restartWrite
external :: &
quit
class (tNode), pointer :: &
num_grid, &
debug_grid, & ! pointer to grid debug options
config_load, &
load_steps, &
load_step, &
solver, &
initial_conditions, &
ic_thermal, &
thermal, &
step_bc, &
step_mech, &
step_discretization, &
step_deformation, &
@ -109,17 +116,11 @@ program DAMASK_grid
! init DAMASK (all modules)
call CPFEM_initAll
print'(/,a)', ' <<<+- DAMASK_spectral init -+>>>'; flush(IO_STDOUT)
print'(/,a)', ' <<<+- DAMASK_grid init -+>>>'; flush(IO_STDOUT)
print*, 'Shanthraj et al., Handbook of Mechanics of Materials, 2019'
print*, 'https://doi.org/10.1007/978-981-10-6855-3_80'
!--------------------------------------------------------------------------------------------------
! 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 field paramters from numerics file and do sanity checks
@ -130,62 +131,69 @@ program DAMASK_grid
if (stagItMax < 0) call IO_error(301,ext_msg='maxStaggeredIter')
if (maxCutBack < 0) call IO_error(301,ext_msg='maxCutBack')
config_load => YAML_parse_file(trim(interface_loadFile))
solver => config_load%get('solver')
!--------------------------------------------------------------------------------------------------
! assign mechanics solver depending on selected type
debug_grid => config_debug%get('grid',defaultVal=emptyList)
select case (trim(num_grid%get_asString('solver', defaultVal = 'Basic')))
case ('Basic')
mech_init => grid_mech_spectral_basic_init
mech_forward => grid_mech_spectral_basic_forward
mech_solution => grid_mech_spectral_basic_solution
mech_updateCoords => grid_mech_spectral_basic_updateCoords
mech_restartWrite => grid_mech_spectral_basic_restartWrite
nActiveFields = 1
select case (solver%get_asString('mechanical'))
case ('spectral_basic')
mechanical_init => grid_mechanical_spectral_basic_init
mechanical_forward => grid_mechanical_spectral_basic_forward
mechanical_solution => grid_mechanical_spectral_basic_solution
mechanical_updateCoords => grid_mechanical_spectral_basic_updateCoords
mechanical_restartWrite => grid_mechanical_spectral_basic_restartWrite
case ('Polarisation')
mech_init => grid_mech_spectral_polarisation_init
mech_forward => grid_mech_spectral_polarisation_forward
mech_solution => grid_mech_spectral_polarisation_solution
mech_updateCoords => grid_mech_spectral_polarisation_updateCoords
mech_restartWrite => grid_mech_spectral_polarisation_restartWrite
case ('spectral_polarization')
mechanical_init => grid_mechanical_spectral_polarisation_init
mechanical_forward => grid_mechanical_spectral_polarisation_forward
mechanical_solution => grid_mechanical_spectral_polarisation_solution
mechanical_updateCoords => grid_mechanical_spectral_polarisation_updateCoords
mechanical_restartWrite => grid_mechanical_spectral_polarisation_restartWrite
case ('FEM')
mech_init => grid_mech_FEM_init
mech_forward => grid_mech_FEM_forward
mech_solution => grid_mech_FEM_solution
mech_updateCoords => grid_mech_FEM_updateCoords
mech_restartWrite => grid_mech_FEM_restartWrite
mechanical_init => grid_mechanical_FEM_init
mechanical_forward => grid_mechanical_FEM_forward
mechanical_solution => grid_mechanical_FEM_solution
mechanical_updateCoords => grid_mechanical_FEM_updateCoords
mechanical_restartWrite => grid_mechanical_FEM_restartWrite
case default
call IO_error(error_ID = 891, ext_msg = trim(num_grid%get_asString('solver')))
call IO_error(error_ID = 891, ext_msg = trim(solver%get_asString('mechanical')))
end select
!--------------------------------------------------------------------------------------------------
! initialize field solver information
if (solver%get_asString('thermal',defaultVal = 'n/a') == 'spectral') nActiveFields = nActiveFields + 1
if (solver%get_asString('damage', defaultVal = 'n/a') == 'spectral') nActiveFields = nActiveFields + 1
allocate(solres(nActiveFields))
allocate( ID(nActiveFields))
field = 1
ID(field) = FIELD_MECH_ID ! mechanical active by default
thermalActive: if (solver%get_asString('thermal',defaultVal = 'n/a') == 'spectral') then
field = field + 1
ID(field) = FIELD_THERMAL_ID
endif thermalActive
damageActive: if (solver%get_asString('damage',defaultVal = 'n/a') == 'spectral') then
field = field + 1
ID(field) = FIELD_DAMAGE_ID
endif damageActive
!--------------------------------------------------------------------------------------------------
! reading information from load case file and to sanity checks
config_load => YAML_parse_file(trim(interface_loadFile))
load_steps => config_load%get('step')
load_steps => config_load%get('loadstep')
allocate(loadCases(load_steps%length)) ! array of load cases
do l = 1, load_steps%length
allocate(loadCases(l)%ID(nActiveFields))
field = 1
loadCases(l)%ID(field) = FIELD_MECH_ID ! mechanical active by default
thermalActive: if (any(thermal_type == THERMAL_conduction_ID)) then
field = field + 1
loadCases(l)%ID(field) = FIELD_THERMAL_ID
endif thermalActive
damageActive: if (any(damage_type == DAMAGE_nonlocal_ID)) then
field = field + 1
loadCases(l)%ID(field) = FIELD_DAMAGE_ID
endif damageActive
load_step => load_steps%get(l)
step_mech => load_step%get('mechanics')
step_bc => load_step%get('boundary_conditions')
step_mech => step_bc%get('mechanical')
loadCases(l)%stress%myType=''
readMech: do m = 1, step_mech%length
select case (step_mech%getKey(m))
@ -217,21 +225,19 @@ program DAMASK_grid
if (.not. allocated(loadCases(l)%deformation%myType)) call IO_error(error_ID=837,ext_msg = 'L/dot_F/F missing')
step_discretization => load_step%get('discretization')
if(.not. step_discretization%contains('t')) call IO_error(error_ID=837,ext_msg = 't missing')
if(.not. step_discretization%contains('N')) call IO_error(error_ID=837,ext_msg = 'N missing')
if (.not. step_discretization%contains('t')) call IO_error(error_ID=837,ext_msg = 't missing')
if (.not. step_discretization%contains('N')) call IO_error(error_ID=837,ext_msg = 'N missing')
loadCases(l)%t = step_discretization%get_asFloat('t')
loadCases(l)%N = step_discretization%get_asInt ('N')
loadCases(l)%r = step_discretization%get_asFloat('r', defaultVal= 1.0_pReal)
loadCases(l)%f_out = step_discretization%get_asInt ('f_out', defaultVal=1)
loadCases(l)%f_restart = step_discretization%get_asInt ('f_restart', defaultVal=huge(0))
loadCases(l)%drop_guessing = (load_step%get_asBool('drop_guessing',defaultVal=.false.) .or. &
merge(.false.,.true.,l > 1))
loadCases(l)%f_restart = load_step%get_asInt('f_restart', defaultVal=huge(0))
loadCases(l)%f_out = load_step%get_asInt('f_out', defaultVal=1)
loadCases(l)%estimate_rate = (load_step%get_asBool('estimate_rate',defaultVal=.true.) .and. l>1)
reportAndCheck: if (worldrank == 0) then
write (loadcase_string, '(i0)' ) l
print'(/,a,i0)', ' load case: ', l
print*, ' drop_guessing:', loadCases(l)%drop_guessing
print*, ' estimate_rate:', loadCases(l)%estimate_rate
if (loadCases(l)%deformation%myType == 'L') then
do j = 1, 3
if (any(loadCases(l)%deformation%mask(j,1:3) .eqv. .true.) .and. &
@ -283,13 +289,13 @@ program DAMASK_grid
else
print'(a,f0.3)', ' r: ', loadCases(l)%r
endif
print'(a,f0.3)', ' t: ', loadCases(l)%t
print'(a,i0)', ' N: ', loadCases(l)%N
print'(a,i0)', ' f_out: ', loadCases(l)%f_out
print'(a,f0.3)', ' t: ', loadCases(l)%t
print'(a,i0)', ' N: ', loadCases(l)%N
print'(a,i0)', ' f_out: ', loadCases(l)%f_out
if (loadCases(l)%f_restart < huge(0)) &
print'(a,i0)', ' f_restart: ', loadCases(l)%f_restart
print'(a,i0)', ' f_restart: ', loadCases(l)%f_restart
if (errorID > 0) call IO_error(error_ID = errorID, ext_msg = loadcase_string) ! exit with error message
if (errorID > 0) call IO_error(error_ID = errorID, el = l)
endif reportAndCheck
enddo
@ -298,12 +304,14 @@ program DAMASK_grid
! doing initialization depending on active solvers
call spectral_Utilities_init
do field = 1, nActiveFields
select case (loadCases(1)%ID(field))
select case (ID(field))
case(FIELD_MECH_ID)
call mech_init
call mechanical_init
case(FIELD_THERMAL_ID)
call grid_thermal_spectral_init
initial_conditions => config_load%get('initial_conditions',defaultVal=emptyDict)
thermal => initial_conditions%get('thermal',defaultVal=emptyDict)
call grid_thermal_spectral_init(thermal%get_asFloat('T',defaultVal = T_0))
case(FIELD_DAMAGE_ID)
call grid_damage_spectral_init
@ -331,7 +339,7 @@ program DAMASK_grid
loadCaseLooping: do l = 1, size(loadCases)
time0 = time ! load case start time
guess = .not. loadCases(l)%drop_guessing ! change of load case? homogeneous guess for the first inc
guess = loadCases(l)%estimate_rate ! change of load case? homogeneous guess for the first inc
incLooping: do inc = 1, loadCases(l)%N
totalIncsCounter = totalIncsCounter + 1
@ -374,9 +382,9 @@ program DAMASK_grid
!--------------------------------------------------------------------------------------------------
! forward fields
do field = 1, nActiveFields
select case(loadCases(l)%ID(field))
select case(ID(field))
case(FIELD_MECH_ID)
call mech_forward (&
call mechanical_forward (&
cutBack,guess,timeinc,timeIncOld,remainingLoadCaseTime, &
deformation_BC = loadCases(l)%deformation, &
stress_BC = loadCases(l)%stress, &
@ -394,9 +402,9 @@ program DAMASK_grid
stagIterate = .true.
do while (stagIterate)
do field = 1, nActiveFields
select case(loadCases(l)%ID(field))
select case(ID(field))
case(FIELD_MECH_ID)
solres(field) = mech_solution(incInfo)
solres(field) = mechanical_solution(incInfo)
case(FIELD_THERMAL_ID)
solres(field) = grid_thermal_spectral_solution(timeinc)
case(FIELD_DAMAGE_ID)
@ -417,13 +425,13 @@ program DAMASK_grid
if ( (all(solres(:)%converged .and. solres(:)%stagConverged)) & ! converged
.and. .not. solres(1)%termIll) then ! and acceptable solution found
call mech_updateCoords
call mechanical_updateCoords
timeIncOld = timeinc
cutBack = .false.
guess = .true. ! start guessing after first converged (sub)inc
if (worldrank == 0) then
write(statUnit,*) totalIncsCounter, time, cutBackLevel, &
solres%converged, solres%iterationsNeeded
solres(1)%converged, solres(1)%iterationsNeeded
flush(statUnit)
endif
elseif (cutBackLevel < maxCutBack) then ! further cutbacking tolerated?
@ -449,18 +457,27 @@ program DAMASK_grid
print'(/,a,i0,a)', ' increment ', totalIncsCounter, ' NOT converged'
endif; flush(IO_STDOUT)
if (mod(inc,loadCases(l)%f_out) == 0) then
call MPI_Allreduce(interface_SIGUSR1,signal,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr)
if (ierr /= 0) error stop 'MPI error'
if (mod(inc,loadCases(l)%f_out) == 0 .or. signal) then
print'(1/,a)', ' ... writing results to file ......................................'
flush(IO_STDOUT)
call CPFEM_results(totalIncsCounter,time)
endif
if (mod(inc,loadCases(l)%f_restart) == 0) then
call mech_restartWrite
if(signal) call interface_setSIGUSR1(.false.)
call MPI_Allreduce(interface_SIGUSR2,signal,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr)
if (ierr /= 0) error stop 'MPI error'
if (mod(inc,loadCases(l)%f_restart) == 0 .or. signal) then
call mechanical_restartWrite
call CPFEM_restartWrite
endif
if(signal) call interface_setSIGUSR2(.false.)
call MPI_Allreduce(interface_SIGTERM,signal,1,MPI_LOGICAL,MPI_LOR,PETSC_COMM_WORLD,ierr)
if (ierr /= 0) error stop 'MPI error'
if (signal) exit loadCaseLooping
endif skipping
enddo incLooping
enddo incLooping
enddo loadCaseLooping

View File

@ -68,8 +68,11 @@ subroutine discretization_grid_init(restart)
print'(/,a)', ' <<<+- discretization_grid init -+>>>'; flush(IO_STDOUT)
if(worldrank == 0) call readVTR(grid,geomSize,origin,materialAt_global)
if(worldrank == 0) then
call readVTR(grid,geomSize,origin,materialAt_global)
else
allocate(materialAt_global(0)) ! needed for IntelMPI
endif
call MPI_Bcast(grid,3,MPI_INTEGER,0,PETSC_COMM_WORLD, ierr)
if (ierr /= 0) error stop 'MPI error'

View File

@ -15,10 +15,10 @@ module grid_damage_spectral
use IO
use spectral_utilities
use discretization_grid
use damage_nonlocal
use YAML_types
use homogenization
use config
implicit none
private
@ -43,13 +43,13 @@ module grid_damage_spectral
phi_current, & !< field of current damage
phi_lastInc, & !< field of previous damage
phi_stagInc !< field of staggered damage
!--------------------------------------------------------------------------------------------------
! reference diffusion tensor, mobility etc.
! reference diffusion tensor, mobility etc.
integer :: totalIter = 0 !< total iteration in current increment
real(pReal), dimension(3,3) :: K_ref
real(pReal) :: mu_ref
public :: &
grid_damage_spectral_init, &
grid_damage_spectral_solution, &
@ -62,8 +62,8 @@ contains
! ToDo: Restart not implemented
!--------------------------------------------------------------------------------------------------
subroutine grid_damage_spectral_init
PetscInt, dimension(0:worldsize-1) :: localK
PetscInt, dimension(0:worldsize-1) :: localK
DM :: damage_grid
Vec :: uBound, lBound
PetscErrorCode :: ierr
@ -72,22 +72,22 @@ subroutine grid_damage_spectral_init
num_generic
character(len=pStringLen) :: &
snes_type
print'(/,a)', ' <<<+- grid_spectral_damage init -+>>>'
print*, 'Shanthraj et al., Handbook of Mechanics of Materials, 2019'
print*, 'https://doi.org/10.1007/978-981-10-6855-3_80'
!-------------------------------------------------------------------------------------------------
! read numerical parameters and do sanity checks
num_grid => config_numerics%get('grid',defaultVal=emptyDict)
num%itmax = num_grid%get_asInt ('itmax',defaultVal=250)
num%eps_damage_atol = num_grid%get_asFloat ('eps_damage_atol',defaultVal=1.0e-2_pReal)
num%eps_damage_rtol = num_grid%get_asFloat ('eps_damage_rtol',defaultVal=1.0e-6_pReal)
num_generic => config_numerics%get('generic',defaultVal=emptyDict)
num%residualStiffness = num_generic%get_asFloat('residualStiffness', defaultVal=1.0e-6_pReal)
if (num%residualStiffness < 0.0_pReal) call IO_error(301,ext_msg='residualStiffness')
if (num%itmax <= 1) call IO_error(301,ext_msg='itmax')
if (num%eps_damage_atol <= 0.0_pReal) call IO_error(301,ext_msg='eps_damage_atol')
@ -104,7 +104,7 @@ subroutine grid_damage_spectral_init
!--------------------------------------------------------------------------------------------------
! initialize solver specific parts of PETSc
call SNESCreate(PETSC_COMM_WORLD,damage_snes,ierr); CHKERRQ(ierr)
call SNESSetOptionsPrefix(damage_snes,'damage_',ierr);CHKERRQ(ierr)
call SNESSetOptionsPrefix(damage_snes,'damage_',ierr);CHKERRQ(ierr)
localK = 0
localK(worldrank) = grid3
call MPI_Allreduce(MPI_IN_PLACE,localK,worldsize,MPI_INTEGER,MPI_SUM,PETSC_COMM_WORLD,ierr)
@ -122,7 +122,7 @@ subroutine grid_damage_spectral_init
call DMsetUp(damage_grid,ierr); CHKERRQ(ierr)
call DMCreateGlobalVector(damage_grid,solution_vec,ierr); CHKERRQ(ierr) ! global solution vector (grid x 1, i.e. every def grad tensor)
call DMDASNESSetFunctionLocal(damage_grid,INSERT_VALUES,formResidual,PETSC_NULL_SNES,ierr) ! residual vector of same shape as solution vector
CHKERRQ(ierr)
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. &
@ -137,12 +137,12 @@ subroutine grid_damage_spectral_init
endif
!--------------------------------------------------------------------------------------------------
! init fields
! 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
zend = zstart + zend - 1
allocate(phi_current(grid(1),grid(2),grid3), source=1.0_pReal)
allocate(phi_lastInc(grid(1),grid(2),grid3), source=1.0_pReal)
allocate(phi_stagInc(grid(1),grid(2),grid3), source=1.0_pReal)
@ -157,26 +157,26 @@ end subroutine grid_damage_spectral_init
!> @brief solution for the spectral damage scheme with internal iterations
!--------------------------------------------------------------------------------------------------
function grid_damage_spectral_solution(timeinc) result(solution)
real(pReal), intent(in) :: &
timeinc !< increment in time for current solution
integer :: i, j, k, cell
integer :: i, j, k, ce
type(tSolutionState) :: solution
PetscInt :: devNull
PetscReal :: phi_min, phi_max, stagNorm, solnNorm
PetscErrorCode :: ierr
SNESConvergedReason :: reason
solution%converged =.false.
!--------------------------------------------------------------------------------------------------
! set module wide availabe data
! set module wide availabe data
params%timeinc = timeinc
call SNESSolve(damage_snes,PETSC_NULL_VEC,solution_vec,ierr); CHKERRQ(ierr)
call SNESGetConvergedReason(damage_snes,reason,ierr); CHKERRQ(ierr)
if (reason < 1) then
solution%converged = .false.
solution%iterationsNeeded = num%itmax
@ -192,20 +192,20 @@ function grid_damage_spectral_solution(timeinc) result(solution)
solution%stagConverged = stagNorm < max(num%eps_damage_atol, num%eps_damage_rtol*solnNorm)
!--------------------------------------------------------------------------------------------------
! updating damage state
cell = 0
! updating damage state
ce = 0
do k = 1, grid3; do j = 1, grid(2); do i = 1,grid(1)
cell = cell + 1
call damage_nonlocal_putNonLocalDamage(phi_current(i,j,k),1,cell)
ce = ce + 1
call damage_nonlocal_putNonLocalDamage(phi_current(i,j,k),ce)
enddo; enddo; enddo
call VecMin(solution_vec,devNull,phi_min,ierr); CHKERRQ(ierr)
call VecMax(solution_vec,devNull,phi_max,ierr); CHKERRQ(ierr)
if (solution%converged) &
print'(/,a)', ' ... nonlocal damage converged .....................................'
print'(/,a,f8.6,2x,f8.6,2x,e11.4)', ' Minimum|Maximum|Delta Damage = ', phi_min, phi_max, stagNorm
print'(/,a)', ' ==========================================================================='
flush(IO_STDOUT)
flush(IO_STDOUT)
end function grid_damage_spectral_solution
@ -214,31 +214,31 @@ end function grid_damage_spectral_solution
!> @brief spectral damage forwarding routine
!--------------------------------------------------------------------------------------------------
subroutine grid_damage_spectral_forward(cutBack)
logical, intent(in) :: cutBack
integer :: i, j, k, cell
integer :: i, j, k, ce
DM :: dm_local
PetscScalar, dimension(:,:,:), pointer :: x_scal
PetscErrorCode :: ierr
if (cutBack) then
if (cutBack) then
phi_current = phi_lastInc
phi_stagInc = phi_lastInc
!--------------------------------------------------------------------------------------------------
! reverting damage field state
cell = 0
! reverting damage field state
ce = 0
call SNESGetDM(damage_snes,dm_local,ierr); CHKERRQ(ierr)
call DMDAVecGetArrayF90(dm_local,solution_vec,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with
x_scal(xstart:xend,ystart:yend,zstart:zend) = phi_current
call DMDAVecRestoreArrayF90(dm_local,solution_vec,x_scal,ierr); CHKERRQ(ierr)
do k = 1, grid3; do j = 1, grid(2); do i = 1,grid(1)
cell = cell + 1
call damage_nonlocal_putNonLocalDamage(phi_current(i,j,k),1,cell)
ce = ce + 1
call damage_nonlocal_putNonLocalDamage(phi_current(i,j,k),ce)
enddo; enddo; enddo
else
phi_lastInc = phi_current
call updateReference
endif
endif
end subroutine grid_damage_spectral_forward
@ -247,7 +247,7 @@ end subroutine grid_damage_spectral_forward
!> @brief forms the spectral damage residual vector
!--------------------------------------------------------------------------------------------------
subroutine formResidual(in,x_scal,f_scal,dummy,ierr)
DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: &
in
PetscScalar, dimension( &
@ -258,31 +258,31 @@ subroutine formResidual(in,x_scal,f_scal,dummy,ierr)
f_scal
PetscObject :: dummy
PetscErrorCode :: ierr
integer :: i, j, k, cell
integer :: i, j, k, ce
real(pReal) :: phiDot, dPhiDot_dPhi, mobility
phi_current = x_scal
phi_current = x_scal
!--------------------------------------------------------------------------------------------------
! evaluate polarization field
scalarField_real = 0.0_pReal
scalarField_real(1:grid(1),1:grid(2),1:grid3) = phi_current
scalarField_real(1:grid(1),1:grid(2),1:grid3) = phi_current
call utilities_FFTscalarForward
call utilities_fourierScalarGradient !< calculate gradient of damage field
call utilities_FFTvectorBackward
cell = 0
ce = 0
do k = 1, grid3; do j = 1, grid(2); do i = 1,grid(1)
cell = cell + 1
vectorField_real(1:3,i,j,k) = matmul(damage_nonlocal_getDiffusion(1,cell) - K_ref, &
ce = ce + 1
vectorField_real(1:3,i,j,k) = matmul(damage_nonlocal_getDiffusion(ce) - K_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
ce = 0
do k = 1, grid3; do j = 1, grid(2); do i = 1,grid(1)
cell = cell + 1
call damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi_current(i,j,k), 1, cell)
mobility = damage_nonlocal_getMobility(1,cell)
ce = ce + 1
call damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi_current(i,j,k),ce)
mobility = damage_nonlocal_getMobility(ce)
scalarField_real(i,j,k) = params%timeinc*(scalarField_real(i,j,k) + phiDot) &
+ mobility*(phi_lastInc(i,j,k) - phi_current(i,j,k)) &
+ mu_ref*phi_current(i,j,k)
@ -297,7 +297,7 @@ subroutine formResidual(in,x_scal,f_scal,dummy,ierr)
scalarField_real(1:grid(1),1:grid(2),1:grid3) = phi_lastInc
where(scalarField_real(1:grid(1),1:grid(2),1:grid3) < num%residualStiffness) &
scalarField_real(1:grid(1),1:grid(2),1:grid3) = num%residualStiffness
!--------------------------------------------------------------------------------------------------
! constructing residual
f_scal = scalarField_real(1:grid(1),1:grid(2),1:grid3) - phi_current
@ -310,15 +310,15 @@ end subroutine formResidual
!--------------------------------------------------------------------------------------------------
subroutine updateReference
integer :: i,j,k,cell,ierr
cell = 0
integer :: i,j,k,ce,ierr
ce = 0
K_ref = 0.0_pReal
mu_ref = 0.0_pReal
do k = 1, grid3; do j = 1, grid(2); do i = 1,grid(1)
cell = cell + 1
K_ref = K_ref + damage_nonlocal_getDiffusion(1,cell)
mu_ref = mu_ref + damage_nonlocal_getMobility(1,cell)
ce = ce + 1
K_ref = K_ref + damage_nonlocal_getDiffusion(ce)
mu_ref = mu_ref + damage_nonlocal_getMobility(ce)
enddo; enddo; enddo
K_ref = K_ref*wgt
call MPI_Allreduce(MPI_IN_PLACE,K_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr)

View File

@ -4,7 +4,7 @@
!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH
!> @brief Grid solver for mechanics: FEM
!--------------------------------------------------------------------------------------------------
module grid_mech_FEM
module grid_mechanical_FEM
#include <petsc/finclude/petscsnes.h>
#include <petsc/finclude/petscdmda.h>
use PETScdmda
@ -45,8 +45,8 @@ module grid_mech_FEM
!--------------------------------------------------------------------------------------------------
! PETSc data
DM :: mech_grid
SNES :: mech_snes
DM :: mechanical_grid
SNES :: mechanical_snes
Vec :: solution_current, solution_lastInc, solution_rate
!--------------------------------------------------------------------------------------------------
@ -79,18 +79,18 @@ module grid_mech_FEM
totalIter = 0 !< total iteration in current increment
public :: &
grid_mech_FEM_init, &
grid_mech_FEM_solution, &
grid_mech_FEM_forward, &
grid_mech_FEM_updateCoords, &
grid_mech_FEM_restartWrite
grid_mechanical_FEM_init, &
grid_mechanical_FEM_solution, &
grid_mechanical_FEM_forward, &
grid_mechanical_FEM_updateCoords, &
grid_mechanical_FEM_restartWrite
contains
!--------------------------------------------------------------------------------------------------
!> @brief allocates all necessary fields and fills them with data, potentially from restart info
!--------------------------------------------------------------------------------------------------
subroutine grid_mech_FEM_init
subroutine grid_mechanical_FEM_init
real(pReal), parameter :: HGCoeff = 0.0e-2_pReal
real(pReal), parameter, dimension(4,8) :: &
@ -108,13 +108,11 @@ subroutine grid_mech_FEM_init
u_current,u_lastInc
PetscInt, dimension(0:worldsize-1) :: localK
integer(HID_T) :: fileHandle, groupHandle
character(len=pStringLen) :: &
fileName
class(tNode), pointer :: &
num_grid, &
debug_grid
print'(/,a)', ' <<<+- grid_mech_FEM init -+>>>'; flush(IO_STDOUT)
print'(/,a)', ' <<<+- grid_mechanical_FEM init -+>>>'; flush(IO_STDOUT)
!-------------------------------------------------------------------------------------------------
! debugging options
@ -141,8 +139,11 @@ subroutine grid_mech_FEM_init
!--------------------------------------------------------------------------------------------------
! set default and user defined options for PETSc
call PetscOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type newtonls -mech_ksp_type fgmres &
&-mech_ksp_max_it 25 -mech_pc_type ml -mech_mg_levels_ksp_type chebyshev',ierr)
call PetscOptionsInsertString(PETSC_NULL_OPTIONS, &
'-mechanical_snes_type newtonls -mechanical_ksp_type fgmres &
&-mechanical_ksp_max_it 25 -mechanical_pc_type ml &
&-mechanical_mg_levels_ksp_type chebyshev', &
ierr)
CHKERRQ(ierr)
call PetscOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr)
CHKERRQ(ierr)
@ -155,8 +156,10 @@ subroutine grid_mech_FEM_init
!--------------------------------------------------------------------------------------------------
! initialize solver specific parts of PETSc
call SNESCreate(PETSC_COMM_WORLD,mech_snes,ierr); CHKERRQ(ierr)
call SNESSetOptionsPrefix(mech_snes,'mech_',ierr);CHKERRQ(ierr)
call SNESCreate(PETSC_COMM_WORLD,mechanical_snes,ierr)
CHKERRQ(ierr)
call SNESSetOptionsPrefix(mechanical_snes,'mechanical_',ierr)
CHKERRQ(ierr)
localK = 0
localK(worldrank) = grid3
call MPI_Allreduce(MPI_IN_PLACE,localK,worldsize,MPI_INTEGER,MPI_SUM,PETSC_COMM_WORLD,ierr)
@ -167,34 +170,44 @@ subroutine grid_mech_FEM_init
1, 1, worldsize, &
3, 1, &
[grid(1)],[grid(2)],localK, &
mech_grid,ierr)
mechanical_grid,ierr)
CHKERRQ(ierr)
call SNESSetDM(mech_snes,mech_grid,ierr); CHKERRQ(ierr)
call DMsetFromOptions(mech_grid,ierr); CHKERRQ(ierr)
call DMsetUp(mech_grid,ierr); CHKERRQ(ierr)
call DMDASetUniformCoordinates(mech_grid,0.0_pReal,geomSize(1),0.0_pReal,geomSize(2),0.0_pReal,geomSize(3),ierr)
call SNESSetDM(mechanical_snes,mechanical_grid,ierr)
CHKERRQ(ierr)
call DMCreateGlobalVector(mech_grid,solution_current,ierr); CHKERRQ(ierr)
call DMCreateGlobalVector(mech_grid,solution_lastInc,ierr); CHKERRQ(ierr)
call DMCreateGlobalVector(mech_grid,solution_rate ,ierr); CHKERRQ(ierr)
call DMSNESSetFunctionLocal(mech_grid,formResidual,PETSC_NULL_SNES,ierr)
call DMsetFromOptions(mechanical_grid,ierr)
CHKERRQ(ierr)
call DMSNESSetJacobianLocal(mech_grid,formJacobian,PETSC_NULL_SNES,ierr)
call DMsetUp(mechanical_grid,ierr)
CHKERRQ(ierr)
call SNESSetConvergenceTest(mech_snes,converged,PETSC_NULL_SNES,PETSC_NULL_FUNCTION,ierr) ! specify custom convergence check function "_converged"
call DMDASetUniformCoordinates(mechanical_grid,0.0_pReal,geomSize(1),0.0_pReal,geomSize(2),0.0_pReal,geomSize(3),ierr)
CHKERRQ(ierr)
call DMCreateGlobalVector(mechanical_grid,solution_current,ierr)
CHKERRQ(ierr)
call DMCreateGlobalVector(mechanical_grid,solution_lastInc,ierr)
CHKERRQ(ierr)
call DMCreateGlobalVector(mechanical_grid,solution_rate ,ierr)
CHKERRQ(ierr)
call DMSNESSetFunctionLocal(mechanical_grid,formResidual,PETSC_NULL_SNES,ierr)
CHKERRQ(ierr)
call DMSNESSetJacobianLocal(mechanical_grid,formJacobian,PETSC_NULL_SNES,ierr)
CHKERRQ(ierr)
call SNESSetConvergenceTest(mechanical_snes,converged,PETSC_NULL_SNES,PETSC_NULL_FUNCTION,ierr) ! specify custom convergence check function "_converged"
CHKERRQ(ierr)
call SNESSetMaxLinearSolveFailures(mechanical_snes, huge(1), ierr) ! ignore linear solve failures
CHKERRQ(ierr)
call SNESSetFromOptions(mechanical_snes,ierr) ! pull it all together with additional cli arguments
CHKERRQ(ierr)
call SNESSetMaxLinearSolveFailures(mech_snes, huge(1), ierr); CHKERRQ(ierr) ! ignore linear solve failures
call SNESSetFromOptions(mech_snes,ierr); CHKERRQ(ierr) ! pull it all together with additional cli arguments
!--------------------------------------------------------------------------------------------------
! init fields
call VecSet(solution_current,0.0_pReal,ierr);CHKERRQ(ierr)
call VecSet(solution_lastInc,0.0_pReal,ierr);CHKERRQ(ierr)
call VecSet(solution_rate ,0.0_pReal,ierr);CHKERRQ(ierr)
call DMDAVecGetArrayF90(mech_grid,solution_current,u_current,ierr); CHKERRQ(ierr)
call DMDAVecGetArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr); CHKERRQ(ierr)
call DMDAVecGetArrayF90(mechanical_grid,solution_current,u_current,ierr)
CHKERRQ(ierr)
call DMDAVecGetArrayF90(mechanical_grid,solution_lastInc,u_lastInc,ierr)
CHKERRQ(ierr)
call DMDAGetCorners(mech_grid,xstart,ystart,zstart,xend,yend,zend,ierr) ! local grid extent
call DMDAGetCorners(mechanical_grid,xstart,ystart,zstart,xend,yend,zend,ierr) ! local grid extent
CHKERRQ(ierr)
xend = xstart+xend-1
yend = ystart+yend-1
@ -219,8 +232,7 @@ subroutine grid_mech_FEM_init
restartRead: if (interface_restartInc > 0) then
print'(/,a,i0,a)', ' reading restart data of increment ', interface_restartInc, ' from file'
write(fileName,'(a,a,i0,a)') trim(getSolverJobName()),'_',worldrank,'.hdf5'
fileHandle = HDF5_openFile(fileName)
fileHandle = HDF5_openFile(getSolverJobName()//'_restart.hdf5','r')
groupHandle = HDF5_openGroup(fileHandle,'solver')
call HDF5_read(groupHandle,P_aim, 'P_aim')
@ -242,9 +254,9 @@ subroutine grid_mech_FEM_init
call utilities_constitutiveResponse(P_current,P_av,C_volAvg,devNull, & ! stress field, stress avg, global average of stiffness and (min+max)/2
F, & ! target F
0.0_pReal) ! time increment
call DMDAVecRestoreArrayF90(mech_grid,solution_current,u_current,ierr)
call DMDAVecRestoreArrayF90(mechanical_grid,solution_current,u_current,ierr)
CHKERRQ(ierr)
call DMDAVecRestoreArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr)
call DMDAVecRestoreArrayF90(mechanical_grid,solution_lastInc,u_lastInc,ierr)
CHKERRQ(ierr)
restartRead2: if (interface_restartInc > 0) then
@ -257,13 +269,13 @@ subroutine grid_mech_FEM_init
endif restartRead2
end subroutine grid_mech_FEM_init
end subroutine grid_mechanical_FEM_init
!--------------------------------------------------------------------------------------------------
!> @brief solution for the FEM scheme with internal iterations
!--------------------------------------------------------------------------------------------------
function grid_mech_FEM_solution(incInfoIn) result(solution)
function grid_mechanical_FEM_solution(incInfoIn) result(solution)
!--------------------------------------------------------------------------------------------------
! input data for solution
@ -284,11 +296,13 @@ function grid_mech_FEM_solution(incInfoIn) result(solution)
!--------------------------------------------------------------------------------------------------
! solve BVP
call SNESsolve(mech_snes,PETSC_NULL_VEC,solution_current,ierr); CHKERRQ(ierr)
call SNESsolve(mechanical_snes,PETSC_NULL_VEC,solution_current,ierr)
CHKERRQ(ierr)
!--------------------------------------------------------------------------------------------------
! check convergence
call SNESGetConvergedReason(mech_snes,reason,ierr); CHKERRQ(ierr)
call SNESGetConvergedReason(mechanical_snes,reason,ierr)
CHKERRQ(ierr)
solution%converged = reason > 0
solution%iterationsNeeded = totalIter
@ -296,14 +310,14 @@ function grid_mech_FEM_solution(incInfoIn) result(solution)
terminallyIll = .false.
P_aim = merge(P_aim,P_av,params%stress_mask)
end function grid_mech_FEM_solution
end function grid_mechanical_FEM_solution
!--------------------------------------------------------------------------------------------------
!> @brief forwarding routine
!> @details find new boundary conditions and best F estimate for end of current timestep
!--------------------------------------------------------------------------------------------------
subroutine grid_mech_FEM_forward(cutBack,guess,Delta_t,Delta_t_old,t_remaining,&
subroutine grid_mechanical_FEM_forward(cutBack,guess,Delta_t,Delta_t_old,t_remaining,&
deformation_BC,stress_BC,rotation_BC)
logical, intent(in) :: &
@ -323,8 +337,10 @@ subroutine grid_mech_FEM_forward(cutBack,guess,Delta_t,Delta_t_old,t_remaining,&
u_current,u_lastInc
call DMDAVecGetArrayF90(mech_grid,solution_current,u_current,ierr); CHKERRQ(ierr)
call DMDAVecGetArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr); CHKERRQ(ierr)
call DMDAVecGetArrayF90(mechanical_grid,solution_current,u_current,ierr)
CHKERRQ(ierr)
call DMDAVecGetArrayF90(mechanical_grid,solution_lastInc,u_lastInc,ierr)
CHKERRQ(ierr)
if (cutBack) then
C_volAvg = C_volAvgLastInc
@ -371,8 +387,10 @@ subroutine grid_mech_FEM_forward(cutBack,guess,Delta_t,Delta_t_old,t_remaining,&
call VecAXPY(solution_current,Delta_t,solution_rate,ierr); CHKERRQ(ierr)
call DMDAVecRestoreArrayF90(mech_grid,solution_current,u_current,ierr); CHKERRQ(ierr)
call DMDAVecRestoreArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr); CHKERRQ(ierr)
call DMDAVecRestoreArrayF90(mechanical_grid,solution_current,u_current,ierr)
CHKERRQ(ierr)
call DMDAVecRestoreArrayF90(mechanical_grid,solution_lastInc,u_lastInc,ierr)
CHKERRQ(ierr)
!--------------------------------------------------------------------------------------------------
! set module wide available data
@ -380,36 +398,37 @@ subroutine grid_mech_FEM_forward(cutBack,guess,Delta_t,Delta_t_old,t_remaining,&
params%rotation_BC = rotation_BC
params%timeinc = Delta_t
end subroutine grid_mech_FEM_forward
end subroutine grid_mechanical_FEM_forward
!--------------------------------------------------------------------------------------------------
!> @brief Update coordinates
!--------------------------------------------------------------------------------------------------
subroutine grid_mech_FEM_updateCoords
subroutine grid_mechanical_FEM_updateCoords
call utilities_updateCoords(F)
end subroutine grid_mech_FEM_updateCoords
end subroutine grid_mechanical_FEM_updateCoords
!--------------------------------------------------------------------------------------------------
!> @brief Write current solver and constitutive data for restart to file
!--------------------------------------------------------------------------------------------------
subroutine grid_mech_FEM_restartWrite
subroutine grid_mechanical_FEM_restartWrite
PetscErrorCode :: ierr
integer(HID_T) :: fileHandle, groupHandle
PetscScalar, dimension(:,:,:,:), pointer :: u_current,u_lastInc
character(len=pStringLen) :: fileName
call DMDAVecGetArrayF90(mech_grid,solution_current,u_current,ierr); CHKERRQ(ierr)
call DMDAVecGetArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr); CHKERRQ(ierr)
call DMDAVecGetArrayF90(mechanical_grid,solution_current,u_current,ierr)
CHKERRQ(ierr)
call DMDAVecGetArrayF90(mechanical_grid,solution_lastInc,u_lastInc,ierr)
CHKERRQ(ierr)
print*, 'writing solver data required for restart to file'; flush(IO_STDOUT)
write(fileName,'(a,a,i0,a)') trim(getSolverJobName()),'_',worldrank,'.hdf5'
fileHandle = HDF5_openFile(fileName,'w')
fileHandle = HDF5_openFile(getSolverJobName()//'_restart.hdf5','w')
groupHandle = HDF5_addGroup(fileHandle,'solver')
call HDF5_write(groupHandle,P_aim, 'P_aim')
@ -427,10 +446,12 @@ subroutine grid_mech_FEM_restartWrite
call HDF5_closeGroup(groupHandle)
call HDF5_closeFile(fileHandle)
call DMDAVecRestoreArrayF90(mech_grid,solution_current,u_current,ierr);CHKERRQ(ierr)
call DMDAVecRestoreArrayF90(mech_grid,solution_lastInc,u_lastInc,ierr);CHKERRQ(ierr)
call DMDAVecRestoreArrayF90(mechanical_grid,solution_current,u_current,ierr)
CHKERRQ(ierr)
call DMDAVecRestoreArrayF90(mechanical_grid,solution_lastInc,u_lastInc,ierr)
CHKERRQ(ierr)
end subroutine grid_mech_FEM_restartWrite
end subroutine grid_mechanical_FEM_restartWrite
!--------------------------------------------------------------------------------------------------
@ -498,8 +519,10 @@ subroutine formResidual(da_local,x_local, &
PetscErrorCode :: ierr
real(pReal), dimension(3,3,3,3) :: devNull
call SNESGetNumberFunctionEvals(mech_snes,nfuncs,ierr); CHKERRQ(ierr)
call SNESGetIterationNumber(mech_snes,PETScIter,ierr); CHKERRQ(ierr)
call SNESGetNumberFunctionEvals(mechanical_snes,nfuncs,ierr)
CHKERRQ(ierr)
call SNESGetIterationNumber(mechanical_snes,PETScIter,ierr)
CHKERRQ(ierr)
if (nfuncs == 0 .and. PETScIter == 0) totalIter = -1 ! new increment
@ -679,4 +702,4 @@ subroutine formJacobian(da_local,x_local,Jac_pre,Jac,dummy,ierr)
end subroutine formJacobian
end module grid_mech_FEM
end module grid_mechanical_FEM

View File

@ -4,7 +4,7 @@
!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH
!> @brief Grid solver for mechanics: Spectral basic
!--------------------------------------------------------------------------------------------------
module grid_mech_spectral_basic
module grid_mechanical_spectral_basic
#include <petsc/finclude/petscsnes.h>
#include <petsc/finclude/petscdmda.h>
use PETScdmda
@ -79,18 +79,18 @@ module grid_mech_spectral_basic
totalIter = 0 !< total iteration in current increment
public :: &
grid_mech_spectral_basic_init, &
grid_mech_spectral_basic_solution, &
grid_mech_spectral_basic_forward, &
grid_mech_spectral_basic_updateCoords, &
grid_mech_spectral_basic_restartWrite
grid_mechanical_spectral_basic_init, &
grid_mechanical_spectral_basic_solution, &
grid_mechanical_spectral_basic_forward, &
grid_mechanical_spectral_basic_updateCoords, &
grid_mechanical_spectral_basic_restartWrite
contains
!--------------------------------------------------------------------------------------------------
!> @brief allocates all necessary fields and fills them with data, potentially from restart info
!--------------------------------------------------------------------------------------------------
subroutine grid_mech_spectral_basic_init
subroutine grid_mechanical_spectral_basic_init
real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P
PetscErrorCode :: ierr
@ -99,13 +99,11 @@ subroutine grid_mech_spectral_basic_init
PetscInt, dimension(0:worldsize-1) :: localK
integer(HID_T) :: fileHandle, groupHandle
integer :: fileUnit
character(len=pStringLen) :: &
fileName
class (tNode), pointer :: &
num_grid, &
debug_grid
print'(/,a)', ' <<<+- grid_mech_spectral_basic init -+>>>'; flush(IO_STDOUT)
print'(/,a)', ' <<<+- grid_mechanical_spectral_basic init -+>>>'; flush(IO_STDOUT)
print*, 'Eisenlohr et al., International Journal of Plasticity 46:3753, 2013'
print*, 'https://doi.org/10.1016/j.ijplas.2012.09.012'//IO_EOL
@ -139,7 +137,7 @@ subroutine grid_mech_spectral_basic_init
!--------------------------------------------------------------------------------------------------
! set default and user defined options for PETSc
call PetscOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type ngmres',ierr)
call PetscOptionsInsertString(PETSC_NULL_OPTIONS,'-mechanical_snes_type ngmres',ierr)
CHKERRQ(ierr)
call PetscOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr)
CHKERRQ(ierr)
@ -152,7 +150,7 @@ subroutine grid_mech_spectral_basic_init
!--------------------------------------------------------------------------------------------------
! initialize solver specific parts of PETSc
call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr)
call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr)
call SNESSetOptionsPrefix(snes,'mechanical_',ierr);CHKERRQ(ierr)
localK = 0
localK(worldrank) = grid3
call MPI_Allreduce(MPI_IN_PLACE,localK,worldsize,MPI_INTEGER,MPI_SUM,PETSC_COMM_WORLD,ierr)
@ -182,8 +180,7 @@ subroutine grid_mech_spectral_basic_init
restartRead: if (interface_restartInc > 0) then
print'(/,a,i0,a)', ' reading restart data of increment ', interface_restartInc, ' from file'
write(fileName,'(a,a,i0,a)') trim(getSolverJobName()),'_',worldrank,'.hdf5'
fileHandle = HDF5_openFile(fileName)
fileHandle = HDF5_openFile(getSolverJobName()//'_restart.hdf5','r')
groupHandle = HDF5_openGroup(fileHandle,'solver')
call HDF5_read(groupHandle,P_aim, 'P_aim')
@ -222,13 +219,13 @@ subroutine grid_mech_spectral_basic_init
call utilities_updateGamma(C_minMaxAvg)
call utilities_saveReferenceStiffness
end subroutine grid_mech_spectral_basic_init
end subroutine grid_mechanical_spectral_basic_init
!--------------------------------------------------------------------------------------------------
!> @brief solution for the basic scheme with internal iterations
!--------------------------------------------------------------------------------------------------
function grid_mech_spectral_basic_solution(incInfoIn) result(solution)
function grid_mechanical_spectral_basic_solution(incInfoIn) result(solution)
!--------------------------------------------------------------------------------------------------
! input data for solution
@ -262,14 +259,14 @@ function grid_mech_spectral_basic_solution(incInfoIn) result(solution)
terminallyIll = .false.
P_aim = merge(P_aim,P_av,params%stress_mask)
end function grid_mech_spectral_basic_solution
end function grid_mechanical_spectral_basic_solution
!--------------------------------------------------------------------------------------------------
!> @brief forwarding routine
!> @details find new boundary conditions and best F estimate for end of current timestep
!--------------------------------------------------------------------------------------------------
subroutine grid_mech_spectral_basic_forward(cutBack,guess,Delta_t,Delta_t_old,t_remaining,&
subroutine grid_mechanical_spectral_basic_forward(cutBack,guess,Delta_t,Delta_t_old,t_remaining,&
deformation_BC,stress_BC,rotation_BC)
logical, intent(in) :: &
@ -339,13 +336,13 @@ subroutine grid_mech_spectral_basic_forward(cutBack,guess,Delta_t,Delta_t_old,t_
params%rotation_BC = rotation_BC
params%timeinc = Delta_t
end subroutine grid_mech_spectral_basic_forward
end subroutine grid_mechanical_spectral_basic_forward
!--------------------------------------------------------------------------------------------------
!> @brief Update coordinates
!--------------------------------------------------------------------------------------------------
subroutine grid_mech_spectral_basic_updateCoords
subroutine grid_mechanical_spectral_basic_updateCoords
PetscErrorCode :: ierr
PetscScalar, dimension(:,:,:,:), pointer :: F
@ -354,25 +351,23 @@ subroutine grid_mech_spectral_basic_updateCoords
call utilities_updateCoords(F)
call DMDAVecRestoreArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr)
end subroutine grid_mech_spectral_basic_updateCoords
end subroutine grid_mechanical_spectral_basic_updateCoords
!--------------------------------------------------------------------------------------------------
!> @brief Write current solver and constitutive data for restart to file
!--------------------------------------------------------------------------------------------------
subroutine grid_mech_spectral_basic_restartWrite
subroutine grid_mechanical_spectral_basic_restartWrite
PetscErrorCode :: ierr
integer(HID_T) :: fileHandle, groupHandle
PetscScalar, dimension(:,:,:,:), pointer :: F
character(len=pStringLen) :: fileName
call DMDAVecGetArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr)
print*, 'writing solver data required for restart to file'; flush(IO_STDOUT)
write(fileName,'(a,a,i0,a)') trim(getSolverJobName()),'_',worldrank,'.hdf5'
fileHandle = HDF5_openFile(fileName,'w')
fileHandle = HDF5_openFile(getSolverJobName()//'_restart.hdf5','w')
groupHandle = HDF5_addGroup(fileHandle,'solver')
call HDF5_write(groupHandle,P_aim, 'P_aim')
@ -393,7 +388,7 @@ subroutine grid_mech_spectral_basic_restartWrite
call DMDAVecRestoreArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr)
end subroutine grid_mech_spectral_basic_restartWrite
end subroutine grid_mechanical_spectral_basic_restartWrite
!--------------------------------------------------------------------------------------------------
@ -506,4 +501,4 @@ subroutine formResidual(in, F, &
end subroutine formResidual
end module grid_mech_spectral_basic
end module grid_mechanical_spectral_basic

View File

@ -4,7 +4,7 @@
!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH
!> @brief Grid solver for mechanics: Spectral Polarisation
!--------------------------------------------------------------------------------------------------
module grid_mech_spectral_polarisation
module grid_mechanical_spectral_polarisation
#include <petsc/finclude/petscsnes.h>
#include <petsc/finclude/petscdmda.h>
use PETScdmda
@ -90,18 +90,18 @@ module grid_mech_spectral_polarisation
totalIter = 0 !< total iteration in current increment
public :: &
grid_mech_spectral_polarisation_init, &
grid_mech_spectral_polarisation_solution, &
grid_mech_spectral_polarisation_forward, &
grid_mech_spectral_polarisation_updateCoords, &
grid_mech_spectral_polarisation_restartWrite
grid_mechanical_spectral_polarisation_init, &
grid_mechanical_spectral_polarisation_solution, &
grid_mechanical_spectral_polarisation_forward, &
grid_mechanical_spectral_polarisation_updateCoords, &
grid_mechanical_spectral_polarisation_restartWrite
contains
!--------------------------------------------------------------------------------------------------
!> @brief allocates all necessary fields and fills them with data, potentially from restart info
!--------------------------------------------------------------------------------------------------
subroutine grid_mech_spectral_polarisation_init
subroutine grid_mechanical_spectral_polarisation_init
real(pReal), dimension(3,3,grid(1),grid(2),grid3) :: P
PetscErrorCode :: ierr
@ -112,13 +112,11 @@ subroutine grid_mech_spectral_polarisation_init
PetscInt, dimension(0:worldsize-1) :: localK
integer(HID_T) :: fileHandle, groupHandle
integer :: fileUnit
character(len=pStringLen) :: &
fileName
class (tNode), pointer :: &
num_grid, &
debug_grid
print'(/,a)', ' <<<+- grid_mech_spectral_polarisation init -+>>>'; flush(IO_STDOUT)
print'(/,a)', ' <<<+- grid_mechanical_spectral_polarization init -+>>>'; flush(IO_STDOUT)
print*, 'Shanthraj et al., International Journal of Plasticity 66:3145, 2015'
print*, 'https://doi.org/10.1016/j.ijplas.2014.02.006'
@ -157,7 +155,7 @@ subroutine grid_mech_spectral_polarisation_init
!--------------------------------------------------------------------------------------------------
! set default and user defined options for PETSc
call PetscOptionsInsertString(PETSC_NULL_OPTIONS,'-mech_snes_type ngmres',ierr)
call PetscOptionsInsertString(PETSC_NULL_OPTIONS,'-mechanical_snes_type ngmres',ierr)
CHKERRQ(ierr)
call PetscOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr)
CHKERRQ(ierr)
@ -172,7 +170,7 @@ subroutine grid_mech_spectral_polarisation_init
!--------------------------------------------------------------------------------------------------
! initialize solver specific parts of PETSc
call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr)
call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr)
call SNESSetOptionsPrefix(snes,'mechanical_',ierr);CHKERRQ(ierr)
localK = 0
localK(worldrank) = grid3
call MPI_Allreduce(MPI_IN_PLACE,localK,worldsize,MPI_INTEGER,MPI_SUM,PETSC_COMM_WORLD,ierr)
@ -204,8 +202,7 @@ subroutine grid_mech_spectral_polarisation_init
restartRead: if (interface_restartInc > 0) then
print'(/,a,i0,a)', ' reading restart data of increment ', interface_restartInc, ' from file'
write(fileName,'(a,a,i0,a)') trim(getSolverJobName()),'_',worldrank,'.hdf5'
fileHandle = HDF5_openFile(fileName)
fileHandle = HDF5_openFile(getSolverJobName()//'_restart.hdf5','r')
groupHandle = HDF5_openGroup(fileHandle,'solver')
call HDF5_read(groupHandle,P_aim, 'P_aim')
@ -250,13 +247,13 @@ subroutine grid_mech_spectral_polarisation_init
C_scale = C_minMaxAvg
S_scale = math_invSym3333(C_minMaxAvg)
end subroutine grid_mech_spectral_polarisation_init
end subroutine grid_mechanical_spectral_polarisation_init
!--------------------------------------------------------------------------------------------------
!> @brief solution for the Polarisation scheme with internal iterations
!--------------------------------------------------------------------------------------------------
function grid_mech_spectral_polarisation_solution(incInfoIn) result(solution)
function grid_mechanical_spectral_polarisation_solution(incInfoIn) result(solution)
!--------------------------------------------------------------------------------------------------
! input data for solution
@ -294,14 +291,14 @@ function grid_mech_spectral_polarisation_solution(incInfoIn) result(solution)
terminallyIll = .false.
P_aim = merge(P_aim,P_av,params%stress_mask)
end function grid_mech_spectral_polarisation_solution
end function grid_mechanical_spectral_polarisation_solution
!--------------------------------------------------------------------------------------------------
!> @brief forwarding routine
!> @details find new boundary conditions and best F estimate for end of current timestep
!--------------------------------------------------------------------------------------------------
subroutine grid_mech_spectral_polarisation_forward(cutBack,guess,Delta_t,Delta_t_old,t_remaining,&
subroutine grid_mechanical_spectral_polarisation_forward(cutBack,guess,Delta_t,Delta_t_old,t_remaining,&
deformation_BC,stress_BC,rotation_BC)
logical, intent(in) :: &
@ -393,13 +390,13 @@ subroutine grid_mech_spectral_polarisation_forward(cutBack,guess,Delta_t,Delta_t
params%rotation_BC = rotation_BC
params%timeinc = Delta_t
end subroutine grid_mech_spectral_polarisation_forward
end subroutine grid_mechanical_spectral_polarisation_forward
!--------------------------------------------------------------------------------------------------
!> @brief Update coordinates
!--------------------------------------------------------------------------------------------------
subroutine grid_mech_spectral_polarisation_updateCoords
subroutine grid_mechanical_spectral_polarisation_updateCoords
PetscErrorCode :: ierr
PetscScalar, dimension(:,:,:,:), pointer :: FandF_tau
@ -408,18 +405,17 @@ subroutine grid_mech_spectral_polarisation_updateCoords
call utilities_updateCoords(FandF_tau(0:8,:,:,:))
call DMDAVecRestoreArrayF90(da,solution_vec,FandF_tau,ierr); CHKERRQ(ierr)
end subroutine grid_mech_spectral_polarisation_updateCoords
end subroutine grid_mechanical_spectral_polarisation_updateCoords
!--------------------------------------------------------------------------------------------------
!> @brief Write current solver and constitutive data for restart to file
!--------------------------------------------------------------------------------------------------
subroutine grid_mech_spectral_polarisation_restartWrite
subroutine grid_mechanical_spectral_polarisation_restartWrite
PetscErrorCode :: ierr
integer(HID_T) :: fileHandle, groupHandle
PetscScalar, dimension(:,:,:,:), pointer :: FandF_tau, F, F_tau
character(len=pStringLen) :: fileName
call DMDAVecGetArrayF90(da,solution_vec,FandF_tau,ierr); CHKERRQ(ierr)
F => FandF_tau(0: 8,:,:,:)
@ -427,8 +423,7 @@ subroutine grid_mech_spectral_polarisation_restartWrite
print*, 'writing solver data required for restart to file'; flush(IO_STDOUT)
write(fileName,'(a,a,i0,a)') trim(getSolverJobName()),'_',worldrank,'.hdf5'
fileHandle = HDF5_openFile(fileName,'w')
fileHandle = HDF5_openFile(getSolverJobName()//'_restart.hdf5','w')
groupHandle = HDF5_addGroup(fileHandle,'solver')
call HDF5_write(groupHandle,F_aim, 'P_aim')
@ -450,7 +445,7 @@ subroutine grid_mech_spectral_polarisation_restartWrite
call DMDAVecRestoreArrayF90(da,solution_vec,FandF_tau,ierr); CHKERRQ(ierr)
end subroutine grid_mech_spectral_polarisation_restartWrite
end subroutine grid_mechanical_spectral_polarisation_restartWrite
!--------------------------------------------------------------------------------------------------
@ -618,4 +613,4 @@ subroutine formResidual(in, FandF_tau, &
end subroutine formResidual
end module grid_mech_spectral_polarisation
end module grid_mechanical_spectral_polarisation

View File

@ -15,11 +15,11 @@ module grid_thermal_spectral
use IO
use spectral_utilities
use discretization_grid
use thermal_conduction
use homogenization
use YAML_types
use config
use material
implicit none
private
@ -45,11 +45,11 @@ module grid_thermal_spectral
T_stagInc !< field of staggered temperature
!--------------------------------------------------------------------------------------------------
! reference diffusion tensor, mobility etc.
! reference diffusion tensor, mobility etc.
integer :: totalIter = 0 !< total iteration in current increment
real(pReal), dimension(3,3) :: K_ref
real(pReal) :: mu_ref
public :: &
grid_thermal_spectral_init, &
grid_thermal_spectral_solution, &
@ -61,10 +61,12 @@ contains
!> @brief allocates all neccessary fields and fills them with data
! ToDo: Restart not implemented
!--------------------------------------------------------------------------------------------------
subroutine grid_thermal_spectral_init
subroutine grid_thermal_spectral_init(T_0)
PetscInt, dimension(0:worldsize-1) :: localK
integer :: i, j, k, cell
real(pReal), intent(in) :: T_0
PetscInt, dimension(0:worldsize-1) :: localK
integer :: i, j, k, ce
DM :: thermal_grid
PetscScalar, dimension(:,:,:), pointer :: x_scal
PetscErrorCode :: ierr
@ -93,11 +95,11 @@ subroutine grid_thermal_spectral_init
CHKERRQ(ierr)
call PetscOptionsInsertString(PETSC_NULL_OPTIONS,num_grid%get_asString('petsc_options',defaultVal=''),ierr)
CHKERRQ(ierr)
!--------------------------------------------------------------------------------------------------
! initialize solver specific parts of PETSc
call SNESCreate(PETSC_COMM_WORLD,thermal_snes,ierr); CHKERRQ(ierr)
call SNESSetOptionsPrefix(thermal_snes,'thermal_',ierr);CHKERRQ(ierr)
call SNESSetOptionsPrefix(thermal_snes,'thermal_',ierr);CHKERRQ(ierr)
localK = 0
localK(worldrank) = grid3
call MPI_Allreduce(MPI_IN_PLACE,localK,worldsize,MPI_INTEGER,MPI_SUM,PETSC_COMM_WORLD,ierr)
@ -115,25 +117,26 @@ subroutine grid_thermal_spectral_init
call DMsetUp(thermal_grid,ierr); CHKERRQ(ierr)
call DMCreateGlobalVector(thermal_grid,solution_vec,ierr); CHKERRQ(ierr) ! global solution vector (grid x 1, i.e. every def grad tensor)
call DMDASNESSetFunctionLocal(thermal_grid,INSERT_VALUES,formResidual,PETSC_NULL_SNES,ierr) ! residual vector of same shape as solution vector
CHKERRQ(ierr)
CHKERRQ(ierr)
call SNESSetFromOptions(thermal_snes,ierr); CHKERRQ(ierr) ! pull it all together with additional CLI arguments
!--------------------------------------------------------------------------------------------------
! init fields
! 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
zend = zstart + zend - 1
allocate(T_current(grid(1),grid(2),grid3), source=0.0_pReal)
allocate(T_lastInc(grid(1),grid(2),grid3), source=0.0_pReal)
allocate(T_stagInc(grid(1),grid(2),grid3), source=0.0_pReal)
cell = 0
ce = 0
do k = 1, grid3; do j = 1, grid(2); do i = 1,grid(1)
cell = cell + 1
T_current(i,j,k) = temperature(material_homogenizationAt(cell))%p(material_homogenizationMemberAt(1,cell))
ce = ce + 1
T_current(i,j,k) = T_0
T_lastInc(i,j,k) = T_current(i,j,k)
T_stagInc(i,j,k) = T_current(i,j,k)
call homogenization_thermal_setField(T_0,0.0_pReal,ce)
enddo; enddo; enddo
call DMDAVecGetArrayF90(thermal_grid,solution_vec,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with
x_scal(xstart:xend,ystart:yend,zstart:zend) = T_current
@ -143,26 +146,26 @@ subroutine grid_thermal_spectral_init
end subroutine grid_thermal_spectral_init
!--------------------------------------------------------------------------------------------------
!> @brief solution for the spectral thermal scheme with internal iterations
!--------------------------------------------------------------------------------------------------
function grid_thermal_spectral_solution(timeinc) result(solution)
real(pReal), intent(in) :: &
timeinc !< increment in time for current solution
integer :: i, j, k, cell
integer :: i, j, k, ce
type(tSolutionState) :: solution
PetscInt :: devNull
PetscReal :: T_min, T_max, stagNorm, solnNorm
PetscErrorCode :: ierr
PetscErrorCode :: ierr
SNESConvergedReason :: reason
solution%converged =.false.
!--------------------------------------------------------------------------------------------------
! set module wide availabe data
! set module wide availabe data
params%timeinc = timeinc
call SNESSolve(thermal_snes,PETSC_NULL_VEC,solution_vec,ierr); CHKERRQ(ierr)
@ -183,13 +186,13 @@ function grid_thermal_spectral_solution(timeinc) result(solution)
solution%stagConverged = stagNorm < max(num%eps_thermal_atol, num%eps_thermal_rtol*solnNorm)
!--------------------------------------------------------------------------------------------------
! updating thermal state
cell = 0
! updating thermal state
ce = 0
do k = 1, grid3; do j = 1, grid(2); do i = 1,grid(1)
cell = cell + 1
call thermal_conduction_putTemperatureAndItsRate(T_current(i,j,k), &
ce = ce + 1
call homogenization_thermal_setField(T_current(i,j,k), &
(T_current(i,j,k)-T_lastInc(i,j,k))/params%timeinc, &
1,cell)
ce)
enddo; enddo; enddo
call VecMin(solution_vec,devNull,T_min,ierr); CHKERRQ(ierr)
@ -198,7 +201,7 @@ function grid_thermal_spectral_solution(timeinc) result(solution)
print'(/,a)', ' ... thermal conduction converged ..................................'
print'(/,a,f8.4,2x,f8.4,2x,f8.4)', ' Minimum|Maximum|Delta Temperature / K = ', T_min, T_max, stagNorm
print'(/,a)', ' ==========================================================================='
flush(IO_STDOUT)
flush(IO_STDOUT)
end function grid_thermal_spectral_solution
@ -207,36 +210,35 @@ end function grid_thermal_spectral_solution
!> @brief forwarding routine
!--------------------------------------------------------------------------------------------------
subroutine grid_thermal_spectral_forward(cutBack)
logical, intent(in) :: cutBack
integer :: i, j, k, cell
integer :: i, j, k, ce
DM :: dm_local
PetscScalar, dimension(:,:,:), pointer :: x_scal
PetscErrorCode :: ierr
if (cutBack) then
if (cutBack) then
T_current = T_lastInc
T_stagInc = T_lastInc
!--------------------------------------------------------------------------------------------------
! reverting thermal field state
cell = 0
! reverting thermal field state
ce = 0
call SNESGetDM(thermal_snes,dm_local,ierr); CHKERRQ(ierr)
call DMDAVecGetArrayF90(dm_local,solution_vec,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with
x_scal(xstart:xend,ystart:yend,zstart:zend) = T_current
call DMDAVecRestoreArrayF90(dm_local,solution_vec,x_scal,ierr); CHKERRQ(ierr)
do k = 1, grid3; do j = 1, grid(2); do i = 1,grid(1)
cell = cell + 1
call thermal_conduction_putTemperatureAndItsRate(T_current(i,j,k), &
(T_current(i,j,k) - &
T_lastInc(i,j,k))/params%timeinc, &
1,cell)
ce = ce + 1
call homogenization_thermal_setField(T_current(i,j,k), &
(T_current(i,j,k)-T_lastInc(i,j,k))/params%timeinc, &
ce)
enddo; enddo; enddo
else
T_lastInc = T_current
call updateReference
endif
end subroutine grid_thermal_spectral_forward
@ -244,7 +246,7 @@ end subroutine grid_thermal_spectral_forward
!> @brief forms the spectral thermal residual vector
!--------------------------------------------------------------------------------------------------
subroutine formResidual(in,x_scal,f_scal,dummy,ierr)
DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: &
in
PetscScalar, dimension( &
@ -255,33 +257,33 @@ subroutine formResidual(in,x_scal,f_scal,dummy,ierr)
f_scal
PetscObject :: dummy
PetscErrorCode :: ierr
integer :: i, j, k, cell
real(pReal) :: Tdot, dTdot_dT
integer :: i, j, k, ce
real(pReal) :: Tdot
T_current = x_scal
T_current = x_scal
!--------------------------------------------------------------------------------------------------
! evaluate polarization field
scalarField_real = 0.0_pReal
scalarField_real(1:grid(1),1:grid(2),1:grid3) = T_current
scalarField_real(1:grid(1),1:grid(2),1:grid3) = T_current
call utilities_FFTscalarForward
call utilities_fourierScalarGradient !< calculate gradient of temperature field
call utilities_FFTvectorBackward
cell = 0
ce = 0
do k = 1, grid3; do j = 1, grid(2); do i = 1,grid(1)
cell = cell + 1
vectorField_real(1:3,i,j,k) = matmul(thermal_conduction_getConductivity(1,cell) - K_ref, &
ce = ce + 1
vectorField_real(1:3,i,j,k) = matmul(thermal_conduction_getConductivity(ce) - K_ref, &
vectorField_real(1:3,i,j,k))
enddo; enddo; enddo
call utilities_FFTvectorForward
call utilities_fourierVectorDivergence !< calculate temperature divergence in fourier field
call utilities_FFTscalarBackward
cell = 0
ce = 0
do k = 1, grid3; do j = 1, grid(2); do i = 1,grid(1)
cell = cell + 1
call thermal_conduction_getSourceAndItsTangent(Tdot, dTdot_dT, T_current(i,j,k), 1, cell)
ce = ce + 1
call thermal_conduction_getSource(Tdot,1,ce)
scalarField_real(i,j,k) = params%timeinc*(scalarField_real(i,j,k) + Tdot) &
+ thermal_conduction_getMassDensity (1,cell)* &
thermal_conduction_getSpecificHeat(1,cell)*(T_lastInc(i,j,k) - &
+ thermal_conduction_getMassDensity (ce)* &
thermal_conduction_getSpecificHeat(ce)*(T_lastInc(i,j,k) - &
T_current(i,j,k))&
+ mu_ref*T_current(i,j,k)
enddo; enddo; enddo
@ -291,7 +293,7 @@ subroutine formResidual(in,x_scal,f_scal,dummy,ierr)
call utilities_FFTscalarForward
call utilities_fourierGreenConvolution(K_ref, mu_ref, params%timeinc)
call utilities_FFTscalarBackward
!--------------------------------------------------------------------------------------------------
! constructing residual
f_scal = T_current - scalarField_real(1:grid(1),1:grid(2),1:grid3)
@ -304,15 +306,15 @@ end subroutine formResidual
!--------------------------------------------------------------------------------------------------
subroutine updateReference
integer :: i,j,k,cell,ierr
cell = 0
integer :: i,j,k,ce,ierr
ce = 0
K_ref = 0.0_pReal
mu_ref = 0.0_pReal
do k = 1, grid3; do j = 1, grid(2); do i = 1,grid(1)
cell = cell + 1
K_ref = K_ref + thermal_conduction_getConductivity(1,cell)
mu_ref = mu_ref + thermal_conduction_getMassDensity(1,cell)* thermal_conduction_getSpecificHeat(1,cell)
ce = ce + 1
K_ref = K_ref + thermal_conduction_getConductivity(ce)
mu_ref = mu_ref + thermal_conduction_getMassDensity(ce)* thermal_conduction_getSpecificHeat(ce)
enddo; enddo; enddo
K_ref = K_ref*wgt
call MPI_Allreduce(MPI_IN_PLACE,K_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr)

View File

@ -10,17 +10,47 @@ module homogenization
use config
use math
use material
use constitutive
use phase
use discretization
use thermal_isothermal
use thermal_conduction
use damage_none
use damage_nonlocal
use HDF5_utilities
use results
use lattice
implicit none
private
enum, bind(c); enumerator :: &
THERMAL_ISOTHERMAL_ID, &
THERMAL_CONDUCTION_ID, &
DAMAGE_NONE_ID, &
DAMAGE_NONLOCAL_ID, &
HOMOGENIZATION_UNDEFINED_ID, &
HOMOGENIZATION_NONE_ID, &
HOMOGENIZATION_ISOSTRAIN_ID, &
HOMOGENIZATION_RGC_ID
end enum
type(tState), allocatable, dimension(:), public :: &
homogState, &
damageState_h
integer(kind(THERMAL_isothermal_ID)), dimension(:), allocatable :: &
thermal_type !< thermal transport model
integer(kind(DAMAGE_none_ID)), dimension(:), allocatable :: &
damage_type !< nonlocal damage model
integer(kind(HOMOGENIZATION_undefined_ID)), dimension(:), allocatable :: &
homogenization_type !< type of each homogenization
type, private :: tNumerics_damage
real(pReal) :: &
charLength !< characteristic length scale for gradient problems
end type tNumerics_damage
type(tNumerics_damage), private :: &
num_damage
logical, public :: &
terminallyIll = .false. !< at least one material point is terminally ill
@ -39,10 +69,6 @@ module homogenization
type :: tNumerics
integer :: &
nMPstate !< materialpoint state loop limit
real(pReal) :: &
subStepMinHomog, & !< minimum (relative) size of sub-step allowed during cutback in homogenization
subStepSizeHomog, & !< size of first substep when cutback in homogenization
stepIncreaseHomog !< increase of next substep size when previous substep converged in homogenization
end type tNumerics
type(tNumerics) :: num
@ -50,48 +76,143 @@ module homogenization
!--------------------------------------------------------------------------------------------------
interface
module subroutine mech_init(num_homog)
module subroutine mechanical_init(num_homog)
class(tNode), pointer, intent(in) :: &
num_homog !< pointer to mechanical homogenization numerics data
end subroutine mech_init
end subroutine mechanical_init
module subroutine mech_partition(subF,ip,el)
module subroutine thermal_init
end subroutine thermal_init
module subroutine damage_init
end subroutine damage_init
module subroutine mechanical_partition(subF,ce)
real(pReal), intent(in), dimension(3,3) :: &
subF
integer, intent(in) :: &
ip, & !< integration point
el !< element number
end subroutine mech_partition
ce
end subroutine mechanical_partition
module subroutine mech_homogenize(ip,el)
module subroutine thermal_partition(ce)
integer, intent(in) :: ce
end subroutine thermal_partition
module subroutine damage_partition(ce)
integer, intent(in) :: ce
end subroutine damage_partition
module subroutine thermal_homogenize(ip,el)
integer, intent(in) :: ip,el
end subroutine thermal_homogenize
module subroutine mechanical_homogenize(dt,ce)
real(pReal), intent(in) :: dt
integer, intent(in) :: &
ip, & !< integration point
el !< element number
end subroutine mech_homogenize
ce !< cell
end subroutine mechanical_homogenize
module subroutine mech_results(group_base,h)
module subroutine mechanical_results(group_base,ho)
character(len=*), intent(in) :: group_base
integer, intent(in) :: h
end subroutine mech_results
integer, intent(in) :: ho
end subroutine mechanical_results
module function mech_updateState(subdt,subF,ip,el) result(doneAndHappy)
module function mechanical_updateState(subdt,subF,ce) result(doneAndHappy)
real(pReal), intent(in) :: &
subdt !< current time step
subdt !< current time step
real(pReal), intent(in), dimension(3,3) :: &
subF
integer, intent(in) :: &
ip, & !< integration point
el !< element number
ce !< cell
logical, dimension(2) :: doneAndHappy
end function mech_updateState
end function mechanical_updateState
module function thermal_conduction_getConductivity(ce) result(K)
integer, intent(in) :: ce
real(pReal), dimension(3,3) :: K
end function thermal_conduction_getConductivity
module function thermal_conduction_getSpecificHeat(ce) result(c_P)
integer, intent(in) :: ce
real(pReal) :: c_P
end function thermal_conduction_getSpecificHeat
module function thermal_conduction_getMassDensity(ce) result(rho)
integer, intent(in) :: ce
real(pReal) :: rho
end function thermal_conduction_getMassDensity
module subroutine homogenization_thermal_setField(T,dot_T, ce)
integer, intent(in) :: ce
real(pReal), intent(in) :: T, dot_T
end subroutine homogenization_thermal_setField
module subroutine thermal_conduction_results(ho,group)
integer, intent(in) :: ho
character(len=*), intent(in) :: group
end subroutine thermal_conduction_results
module function homogenization_thermal_T(ce) result(T)
integer, intent(in) :: ce
real(pReal) :: T
end function homogenization_thermal_T
module subroutine thermal_conduction_getSource(Tdot, ip, el)
integer, intent(in) :: &
ip, &
el
real(pReal), intent(out) :: Tdot
end subroutine thermal_conduction_getSource
module function damage_nonlocal_getMobility(ce) result(M)
integer, intent(in) :: ce
real(pReal) :: M
end function damage_nonlocal_getMobility
module subroutine damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ce)
integer, intent(in) :: ce
real(pReal), intent(in) :: &
phi
real(pReal) :: &
phiDot, dPhiDot_dPhi
end subroutine damage_nonlocal_getSourceAndItsTangent
module subroutine damage_nonlocal_putNonLocalDamage(phi,ce)
integer, intent(in) :: ce
real(pReal), intent(in) :: &
phi
end subroutine damage_nonlocal_putNonLocalDamage
module subroutine damage_nonlocal_results(ho,group)
integer, intent(in) :: ho
character(len=*), intent(in) :: group
end subroutine damage_nonlocal_results
end interface
public :: &
homogenization_init, &
materialpoint_stressAndItsTangent, &
thermal_conduction_getSpecificHeat, &
thermal_conduction_getConductivity, &
thermal_conduction_getMassDensity, &
thermal_conduction_getSource, &
damage_nonlocal_getMobility, &
damage_nonlocal_getSourceAndItsTangent, &
damage_nonlocal_putNonLocalDamage, &
homogenization_thermal_setfield, &
homogenization_thermal_T, &
homogenization_forward, &
homogenization_results
homogenization_results, &
homogenization_restartRead, &
homogenization_restartWrite, &
THERMAL_CONDUCTION_ID, &
DAMAGE_NONLOCAL_ID
public :: &
damage_nonlocal_init, &
damage_nonlocal_getDiffusion
contains
@ -99,7 +220,7 @@ contains
!--------------------------------------------------------------------------------------------------
!> @brief module initialization
!--------------------------------------------------------------------------------------------------
subroutine homogenization_init
subroutine homogenization_init()
class (tNode) , pointer :: &
num_homog, &
@ -107,27 +228,21 @@ subroutine homogenization_init
print'(/,a)', ' <<<+- homogenization init -+>>>'; flush(IO_STDOUT)
allocate(homogState (size(material_name_homogenization)))
allocate(damageState_h (size(material_name_homogenization)))
call material_parseHomogenization()
num_homog => config_numerics%get('homogenization',defaultVal=emptyDict)
num_homogGeneric => num_homog%get('generic',defaultVal=emptyDict)
num%nMPstate = num_homogGeneric%get_asInt ('nMPstate', defaultVal=10)
num%subStepMinHomog = num_homogGeneric%get_asFloat('subStepMin', defaultVal=1.0e-3_pReal)
num%subStepSizeHomog = num_homogGeneric%get_asFloat('subStepSize', defaultVal=0.25_pReal)
num%stepIncreaseHomog = num_homogGeneric%get_asFloat('stepIncrease', defaultVal=1.5_pReal)
num%nMPstate = num_homogGeneric%get_asInt('nMPstate',defaultVal=10)
if (num%nMPstate < 1) call IO_error(301,ext_msg='nMPstate')
if (num%nMPstate < 1) call IO_error(301,ext_msg='nMPstate')
if (num%subStepMinHomog <= 0.0_pReal) call IO_error(301,ext_msg='subStepMinHomog')
if (num%subStepSizeHomog <= 0.0_pReal) call IO_error(301,ext_msg='subStepSizeHomog')
if (num%stepIncreaseHomog <= 0.0_pReal) call IO_error(301,ext_msg='stepIncreaseHomog')
call mech_init(num_homog)
if (any(thermal_type == THERMAL_isothermal_ID)) call thermal_isothermal_init
if (any(thermal_type == THERMAL_conduction_ID)) call thermal_conduction_init
if (any(damage_type == DAMAGE_none_ID)) call damage_none_init
if (any(damage_type == DAMAGE_nonlocal_ID)) call damage_nonlocal_init
call mechanical_init(num_homog)
call thermal_init()
call damage_init()
call damage_nonlocal_init()
end subroutine homogenization_init
@ -144,126 +259,96 @@ subroutine materialpoint_stressAndItsTangent(dt,FEsolving_execIP,FEsolving_execE
NiterationMPstate, &
ip, & !< integration point number
el, & !< element number
myNgrains, co, ce, ho, me
real(pReal) :: &
subFrac, &
subStep
myNgrains, co, ce, ho, me, ph
logical :: &
converged
logical, dimension(2) :: &
doneAndHappy
!$OMP PARALLEL DO PRIVATE(ce,me,ho,myNgrains,NiterationMPstate,subFrac,converged,subStep,doneAndHappy)
!$OMP PARALLEL
!$OMP DO PRIVATE(ce,me,ho,myNgrains,NiterationMPstate,converged,doneAndHappy)
do el = FEsolving_execElem(1),FEsolving_execElem(2)
ho = material_homogenizationAt(el)
myNgrains = homogenization_Nconstituents(ho)
do ip = FEsolving_execIP(1),FEsolving_execIP(2)
me = material_homogenizationMemberAt(ip,el)
!--------------------------------------------------------------------------------------------------
! initialize restoration points
call constitutive_initializeRestorationPoints(ip,el)
ce = (el-1)*discretization_nIPs + ip
me = material_homogenizationMemberAt2(ce)
subFrac = 0.0_pReal
converged = .false. ! pretend failed step ...
subStep = 1.0_pReal/num%subStepSizeHomog ! ... larger then the requested calculation
call phase_restore(ce,.false.) ! wrong name (is more a forward function)
if (homogState(ho)%sizeState > 0) &
homogState(ho)%subState0(:,me) = homogState(ho)%State0(:,me)
if (damageState(ho)%sizeState > 0) &
damageState(ho)%subState0(:,me) = damageState(ho)%State0(:,me)
if(homogState(ho)%sizeState > 0) homogState(ho)%State(:,me) = homogState(ho)%State0(:,me)
if(damageState_h(ho)%sizeState > 0) damageState_h(ho)%State(:,me) = damageState_h(ho)%State0(:,me)
call damage_partition(ce)
cutBackLooping: do while (.not. terminallyIll .and. subStep > num%subStepMinHomog)
doneAndHappy = [.false.,.true.]
if (converged) then
subFrac = subFrac + subStep
subStep = min(1.0_pReal-subFrac,num%stepIncreaseHomog*subStep) ! introduce flexibility for step increase/acceleration
NiterationMPstate = 0
convergenceLooping: do while (.not. (terminallyIll .or. doneAndHappy(1)) &
.and. NiterationMPstate < num%nMPstate)
NiterationMPstate = NiterationMPstate + 1
steppingNeeded: if (subStep > num%subStepMinHomog) then
! wind forward grain starting point
call constitutive_windForward(ip,el)
if (.not. doneAndHappy(1)) then
call mechanical_partition(homogenization_F(1:3,1:3,ce),ce)
converged = .true.
do co = 1, myNgrains
converged = converged .and. crystallite_stress(dt,co,ip,el)
enddo
if(homogState(ho)%sizeState > 0) &
homogState(ho)%subState0(:,me) = homogState(ho)%State(:,me)
if(damageState(ho)%sizeState > 0) &
damageState(ho)%subState0(:,me) = damageState(ho)%State(:,me)
endif steppingNeeded
elseif ( (myNgrains == 1 .and. subStep <= 1.0 ) .or. & ! single grain already tried internal subStepping in crystallite
num%subStepSizeHomog * subStep <= num%subStepMinHomog ) then ! would require too small subStep
! cutback makes no sense
if (.not. terminallyIll) & ! so first signals terminally ill...
print*, ' Integration point ', ip,' at element ', el, ' terminally ill'
terminallyIll = .true. ! ...and kills all others
else ! cutback makes sense
subStep = num%subStepSizeHomog * subStep ! crystallite had severe trouble, so do a significant cutback
call constitutive_restore(ip,el,subStep < 1.0_pReal)
if(homogState(ho)%sizeState > 0) &
homogState(ho)%State(:,me) = homogState(ho)%subState0(:,me)
if(damageState(ho)%sizeState > 0) &
damageState(ho)%State(:,me) = damageState(ho)%subState0(:,me)
if (.not. converged) then
doneAndHappy = [.true.,.false.]
else
doneAndHappy = mechanical_updateState(dt,homogenization_F(1:3,1:3,ce),ce)
converged = all(doneAndHappy)
endif
endif
if (subStep > num%subStepMinHomog) doneAndHappy = [.false.,.true.]
NiterationMPstate = 0
convergenceLooping: do while (.not. terminallyIll &
.and. .not. doneAndHappy(1) &
.and. NiterationMPstate < num%nMPstate)
NiterationMPstate = NiterationMPstate + 1
!--------------------------------------------------------------------------------------------------
! deformation partitioning
if (.not. doneAndHappy(1)) then
ce = (el-1)*discretization_nIPs + ip
call mech_partition(homogenization_F0(1:3,1:3,ce) &
+ (homogenization_F(1:3,1:3,ce)-homogenization_F0(1:3,1:3,ce))&
*(subStep+subFrac), &
ip,el)
converged = .true.
do co = 1, myNgrains
converged = converged .and. crystallite_stress(dt*subStep,co,ip,el)
enddo
if (.not. converged) then
doneAndHappy = [.true.,.false.]
else
ce = (el-1)*discretization_nIPs + ip
doneAndHappy = mech_updateState(dt*subStep, &
homogenization_F0(1:3,1:3,ce) &
+ (homogenization_F(1:3,1:3,ce)-homogenization_F0(1:3,1:3,ce)) &
*(subStep+subFrac), &
ip,el)
converged = all(doneAndHappy)
endif
endif
enddo convergenceLooping
enddo cutBackLooping
enddo convergenceLooping
if (.not. converged) then
if (.not. terminallyIll) print*, ' Integration point ', ip,' at element ', el, ' terminally ill'
terminallyIll = .true.
endif
enddo
enddo
!$OMP END PARALLEL DO
!$OMP END DO
if (.not. terminallyIll ) then
!$OMP PARALLEL DO PRIVATE(ho,myNgrains)
if (.not. terminallyIll) then
!$OMP DO PRIVATE(ho,ph,ce)
do el = FEsolving_execElem(1),FEsolving_execElem(2)
if (terminallyIll) continue
ho = material_homogenizationAt(el)
do ip = FEsolving_execIP(1),FEsolving_execIP(2)
ce = (el-1)*discretization_nIPs + ip
call thermal_partition(ce)
do co = 1, homogenization_Nconstituents(ho)
ph = material_phaseAt(co,el)
if (.not. thermal_stress(dt,ph,material_phaseMemberAt(co,ip,el))) then
if (.not. terminallyIll) & ! so first signals terminally ill...
print*, ' Integration point ', ip,' at element ', el, ' terminally ill'
terminallyIll = .true. ! ...and kills all others
endif
enddo
call thermal_homogenize(ip,el)
enddo
enddo
!$OMP END DO
!$OMP DO PRIVATE(ho,ce)
elementLooping3: do el = FEsolving_execElem(1),FEsolving_execElem(2)
ho = material_homogenizationAt(el)
myNgrains = homogenization_Nconstituents(ho)
IpLooping3: do ip = FEsolving_execIP(1),FEsolving_execIP(2)
do co = 1, myNgrains
ce = (el-1)*discretization_nIPs + ip
do co = 1, homogenization_Nconstituents(ho)
call crystallite_orientations(co,ip,el)
enddo
call mech_homogenize(ip,el)
call mechanical_homogenize(dt,ce)
enddo IpLooping3
enddo elementLooping3
!$OMP END PARALLEL DO
!$OMP END DO
else
print'(/,a,/)', ' << HOMOG >> Material Point terminally ill'
endif
!$OMP END PARALLEL
end subroutine materialpoint_stressAndItsTangent
@ -283,7 +368,7 @@ subroutine homogenization_results
group_base = 'current/homogenization/'//trim(material_name_homogenization(ho))
call results_closeGroup(results_addGroup(group_base))
call mech_results(group_base,ho)
call mechanical_results(group_base,ho)
group = trim(group_base)//'/damage'
call results_closeGroup(results_addGroup(group))
@ -315,9 +400,185 @@ subroutine homogenization_forward
do ho = 1, size(material_name_homogenization)
homogState (ho)%state0 = homogState (ho)%state
damageState(ho)%state0 = damageState(ho)%state
if(damageState_h(ho)%sizeState > 0) &
damageState_h(ho)%state0 = damageState_h(ho)%state
enddo
end subroutine homogenization_forward
!--------------------------------------------------------------------------------------------------
!--------------------------------------------------------------------------------------------------
subroutine homogenization_restartWrite(fileHandle)
integer(HID_T), intent(in) :: fileHandle
integer(HID_T), dimension(2) :: groupHandle
integer :: ho
groupHandle(1) = HDF5_addGroup(fileHandle,'homogenization')
do ho = 1, size(material_name_homogenization)
groupHandle(2) = HDF5_addGroup(groupHandle(1),material_name_homogenization(ho))
call HDF5_write(groupHandle(2),homogState(ho)%state,'omega') ! ToDo: should be done by mech
call HDF5_closeGroup(groupHandle(2))
enddo
call HDF5_closeGroup(groupHandle(1))
end subroutine homogenization_restartWrite
!--------------------------------------------------------------------------------------------------
!--------------------------------------------------------------------------------------------------
subroutine homogenization_restartRead(fileHandle)
integer(HID_T), intent(in) :: fileHandle
integer(HID_T), dimension(2) :: groupHandle
integer :: ho
groupHandle(1) = HDF5_openGroup(fileHandle,'homogenization')
do ho = 1, size(material_name_homogenization)
groupHandle(2) = HDF5_openGroup(groupHandle(1),material_name_homogenization(ho))
call HDF5_read(groupHandle(2),homogState(ho)%state,'omega') ! ToDo: should be done by mech
call HDF5_closeGroup(groupHandle(2))
enddo
call HDF5_closeGroup(groupHandle(1))
end subroutine homogenization_restartRead
!--------------------------------------------------------------------------------------------------
!> @brief module initialization
!> @details reads in material parameters, allocates arrays, and does sanity checks
!--------------------------------------------------------------------------------------------------
subroutine damage_nonlocal_init
integer :: Ninstances,Nmaterialpoints,h
class(tNode), pointer :: &
num_generic, &
material_homogenization
print'(/,a)', ' <<<+- damage_nonlocal init -+>>>'; flush(6)
!------------------------------------------------------------------------------------
! read numerics parameter
num_generic => config_numerics%get('generic',defaultVal= emptyDict)
num_damage%charLength = num_generic%get_asFloat('charLength',defaultVal=1.0_pReal)
Ninstances = count(damage_type == DAMAGE_nonlocal_ID)
material_homogenization => config_material%get('homogenization')
do h = 1, material_homogenization%length
if (damage_type(h) /= DAMAGE_NONLOCAL_ID) cycle
Nmaterialpoints = count(material_homogenizationAt == h)
damageState_h(h)%sizeState = 1
allocate(damageState_h(h)%state0 (1,Nmaterialpoints), source=1.0_pReal)
allocate(damageState_h(h)%state (1,Nmaterialpoints), source=1.0_pReal)
enddo
end subroutine damage_nonlocal_init
!--------------------------------------------------------------------------------------------------
!> @brief returns homogenized non local damage diffusion tensor in reference configuration
!--------------------------------------------------------------------------------------------------
function damage_nonlocal_getDiffusion(ce)
integer, intent(in) :: ce
real(pReal), dimension(3,3) :: &
damage_nonlocal_getDiffusion
integer :: &
ho, &
co
ho = material_homogenizationAt2(ce)
damage_nonlocal_getDiffusion = 0.0_pReal
do co = 1, homogenization_Nconstituents(ho)
damage_nonlocal_getDiffusion = damage_nonlocal_getDiffusion + &
crystallite_push33ToRef(co,ce,lattice_D(1:3,1:3,material_phaseAt2(co,ce)))
enddo
damage_nonlocal_getDiffusion = &
num_damage%charLength**2*damage_nonlocal_getDiffusion/real(homogenization_Nconstituents(ho),pReal)
end function damage_nonlocal_getDiffusion
!--------------------------------------------------------------------------------------------------
!> @brief parses the homogenization part from the material configuration
! ToDo: This should be done in homogenization
!--------------------------------------------------------------------------------------------------
subroutine material_parseHomogenization
class(tNode), pointer :: &
material_homogenization, &
homog, &
homogMech, &
homogThermal, &
homogDamage
integer :: h
material_homogenization => config_material%get('homogenization')
allocate(homogenization_type(size(material_name_homogenization)), source=HOMOGENIZATION_undefined_ID)
allocate(thermal_type(size(material_name_homogenization)), source=THERMAL_isothermal_ID)
allocate(damage_type (size(material_name_homogenization)), source=DAMAGE_none_ID)
do h=1, size(material_name_homogenization)
homog => material_homogenization%get(h)
homogMech => homog%get('mechanics')
select case (homogMech%get_asString('type'))
case('pass')
homogenization_type(h) = HOMOGENIZATION_NONE_ID
case('isostrain')
homogenization_type(h) = HOMOGENIZATION_ISOSTRAIN_ID
case('RGC')
homogenization_type(h) = HOMOGENIZATION_RGC_ID
case default
call IO_error(500,ext_msg=homogMech%get_asString('type'))
end select
if (homog%contains('thermal')) then
homogThermal => homog%get('thermal')
select case (homogThermal%get_asString('type'))
case('pass')
thermal_type(h) = THERMAL_conduction_ID
case default
call IO_error(500,ext_msg=homogThermal%get_asString('type'))
end select
endif
if (homog%contains('damage')) then
homogDamage => homog%get('damage')
select case (homogDamage%get_asString('type'))
case('pass')
damage_type(h) = DAMAGE_nonlocal_ID
case default
call IO_error(500,ext_msg=homogDamage%get_asString('type'))
end select
endif
enddo
end subroutine material_parseHomogenization
end module homogenization

View File

@ -0,0 +1,168 @@
!--------------------------------------------------------------------------------------------------
!> @author Martin Diehl, KU Leuven
!--------------------------------------------------------------------------------------------------
submodule(homogenization) homogenization_damage
use lattice
type :: tDataContainer
real(pReal), dimension(:), allocatable :: phi
end type tDataContainer
type(tDataContainer), dimension(:), allocatable :: current
type :: tParameters
character(len=pStringLen), allocatable, dimension(:) :: &
output
end type tParameters
type(tparameters), dimension(:), allocatable :: &
param
contains
!--------------------------------------------------------------------------------------------------
!> @brief Allocate variables and set parameters.
!--------------------------------------------------------------------------------------------------
module subroutine damage_init()
class(tNode), pointer :: &
configHomogenizations, &
configHomogenization, &
configHomogenizationDamage
integer :: ho
print'(/,a)', ' <<<+- homogenization:damage init -+>>>'
print'(/,a)', ' <<<+- homogenization:damage:isodamage init -+>>>'
configHomogenizations => config_material%get('homogenization')
allocate(param(configHomogenizations%length))
allocate(current(configHomogenizations%length))
do ho = 1, configHomogenizations%length
allocate(current(ho)%phi(count(material_homogenizationAt2==ho)), source=1.0_pReal)
configHomogenization => configHomogenizations%get(ho)
associate(prm => param(ho))
if (configHomogenization%contains('damage')) then
configHomogenizationDamage => configHomogenization%get('damage')
#if defined (__GFORTRAN__)
prm%output = output_asStrings(configHomogenizationDamage)
#else
prm%output = configHomogenizationDamage%get_asStrings('output',defaultVal=emptyStringArray)
#endif
else
prm%output = emptyStringArray
endif
end associate
enddo
end subroutine damage_init
!--------------------------------------------------------------------------------------------------
!> @brief Partition temperature onto the individual constituents.
!--------------------------------------------------------------------------------------------------
module subroutine damage_partition(ce)
real(pReal) :: phi
integer, intent(in) :: ce
integer :: co
if(damageState_h(material_homogenizationAt2(ce))%sizeState < 1) return
phi = damagestate_h(material_homogenizationAt2(ce))%state(1,material_homogenizationMemberAt2(ce))
do co = 1, homogenization_Nconstituents(material_homogenizationAt2(ce))
call phase_damage_set_phi(phi,co,ce)
enddo
end subroutine damage_partition
!--------------------------------------------------------------------------------------------------
!> @brief Returns homogenized nonlocal damage mobility
!--------------------------------------------------------------------------------------------------
module function damage_nonlocal_getMobility(ce) result(M)
integer, intent(in) :: ce
integer :: &
co
real(pReal) :: M
M = 0.0_pReal
do co = 1, homogenization_Nconstituents(material_homogenizationAt2(ce))
M = M + lattice_M(material_phaseAt2(co,ce))
enddo
M = M/real(homogenization_Nconstituents(material_homogenizationAt2(ce)),pReal)
end function damage_nonlocal_getMobility
!--------------------------------------------------------------------------------------------------
!> @brief calculates homogenized damage driving forces
!--------------------------------------------------------------------------------------------------
module subroutine damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, phi, ce)
integer, intent(in) :: ce
real(pReal), intent(in) :: &
phi
real(pReal) :: &
phiDot, dPhiDot_dPhi
phiDot = 0.0_pReal
dPhiDot_dPhi = 0.0_pReal
call phase_damage_getRateAndItsTangents(phiDot, dPhiDot_dPhi, phi, ce)
phiDot = phiDot/real(homogenization_Nconstituents(material_homogenizationAt2(ce)),pReal)
dPhiDot_dPhi = dPhiDot_dPhi/real(homogenization_Nconstituents(material_homogenizationAt2(ce)),pReal)
end subroutine damage_nonlocal_getSourceAndItsTangent
!--------------------------------------------------------------------------------------------------
!> @brief updated nonlocal damage field with solution from damage phase field PDE
!--------------------------------------------------------------------------------------------------
module subroutine damage_nonlocal_putNonLocalDamage(phi,ce)
integer, intent(in) :: ce
real(pReal), intent(in) :: &
phi
integer :: &
ho, &
me
ho = material_homogenizationAt2(ce)
me = material_homogenizationMemberAt2(ce)
damagestate_h(ho)%state(1,me) = phi
end subroutine damage_nonlocal_putNonLocalDamage
!--------------------------------------------------------------------------------------------------
!> @brief writes results to HDF5 output file
!--------------------------------------------------------------------------------------------------
module subroutine damage_nonlocal_results(ho,group)
integer, intent(in) :: ho
character(len=*), intent(in) :: group
integer :: o
associate(prm => param(ho))
outputsLoop: do o = 1,size(prm%output)
select case(prm%output(o))
case ('phi')
call results_writeDataset(group,damagestate_h(ho)%state(1,:),prm%output(o),&
'damage indicator','-')
end select
enddo outputsLoop
end associate
end subroutine damage_nonlocal_results
end submodule homogenization_damage

View File

@ -2,75 +2,72 @@
!> @author Martin Diehl, KU Leuven
!> @brief Partition F and homogenize P/dPdF
!--------------------------------------------------------------------------------------------------
submodule(homogenization) homogenization_mech
submodule(homogenization) mechanical
interface
module subroutine mech_none_init
end subroutine mech_none_init
module subroutine mechanical_pass_init
end subroutine mechanical_pass_init
module subroutine mech_isostrain_init
end subroutine mech_isostrain_init
module subroutine mechanical_isostrain_init
end subroutine mechanical_isostrain_init
module subroutine mech_RGC_init(num_homogMech)
module subroutine mechanical_RGC_init(num_homogMech)
class(tNode), pointer, intent(in) :: &
num_homogMech !< pointer to mechanical homogenization numerics data
end subroutine mech_RGC_init
end subroutine mechanical_RGC_init
module subroutine mech_isostrain_partitionDeformation(F,avgF)
module subroutine mechanical_isostrain_partitionDeformation(F,avgF)
real(pReal), dimension (:,:,:), intent(out) :: F !< partitioned deformation gradient
real(pReal), dimension (3,3), intent(in) :: avgF !< average deformation gradient at material point
end subroutine mech_isostrain_partitionDeformation
end subroutine mechanical_isostrain_partitionDeformation
module subroutine mech_RGC_partitionDeformation(F,avgF,instance,of)
module subroutine mechanical_RGC_partitionDeformation(F,avgF,ce)
real(pReal), dimension (:,:,:), intent(out) :: F !< partitioned deformation gradient
real(pReal), dimension (3,3), intent(in) :: avgF !< average deformation gradient at material point
integer, intent(in) :: &
instance, &
of
end subroutine mech_RGC_partitionDeformation
ce
end subroutine mechanical_RGC_partitionDeformation
module subroutine mech_isostrain_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,instance)
module subroutine mechanical_isostrain_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,ho)
real(pReal), dimension (3,3), intent(out) :: avgP !< average stress at material point
real(pReal), dimension (3,3,3,3), intent(out) :: dAvgPdAvgF !< average stiffness at material point
real(pReal), dimension (:,:,:), intent(in) :: P !< partitioned stresses
real(pReal), dimension (:,:,:,:,:), intent(in) :: dPdF !< partitioned stiffnesses
integer, intent(in) :: instance
end subroutine mech_isostrain_averageStressAndItsTangent
integer, intent(in) :: ho
end subroutine mechanical_isostrain_averageStressAndItsTangent
module subroutine mech_RGC_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,instance)
module subroutine mechanical_RGC_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,ho)
real(pReal), dimension (3,3), intent(out) :: avgP !< average stress at material point
real(pReal), dimension (3,3,3,3), intent(out) :: dAvgPdAvgF !< average stiffness at material point
real(pReal), dimension (:,:,:), intent(in) :: P !< partitioned stresses
real(pReal), dimension (:,:,:,:,:), intent(in) :: dPdF !< partitioned stiffnesses
integer, intent(in) :: instance
end subroutine mech_RGC_averageStressAndItsTangent
integer, intent(in) :: ho
end subroutine mechanical_RGC_averageStressAndItsTangent
module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHappy)
module function mechanical_RGC_updateState(P,F,avgF,dt,dPdF,ce) result(doneAndHappy)
logical, dimension(2) :: doneAndHappy
real(pReal), dimension(:,:,:), intent(in) :: &
P,& !< partitioned stresses
F,& !< partitioned deformation gradients
F0 !< partitioned initial deformation gradients
F !< partitioned deformation gradients
real(pReal), dimension(:,:,:,:,:), intent(in) :: dPdF !< partitioned stiffnesses
real(pReal), dimension(3,3), intent(in) :: avgF !< average F
real(pReal), intent(in) :: dt !< time increment
integer, intent(in) :: &
ip, & !< integration point number
el !< element number
end function mech_RGC_updateState
ce !< cell
end function mechanical_RGC_updateState
module subroutine mech_RGC_results(instance,group)
integer, intent(in) :: instance !< homogenization instance
module subroutine mechanical_RGC_results(ho,group)
integer, intent(in) :: ho !< homogenization type
character(len=*), intent(in) :: group !< group name in HDF5 file
end subroutine mech_RGC_results
end subroutine mechanical_RGC_results
end interface
@ -79,7 +76,7 @@ contains
!--------------------------------------------------------------------------------------------------
!> @brief Allocate variables and set parameters.
!--------------------------------------------------------------------------------------------------
module subroutine mech_init(num_homog)
module subroutine mechanical_init(num_homog)
class(tNode), pointer, intent(in) :: &
num_homog
@ -87,7 +84,7 @@ module subroutine mech_init(num_homog)
class(tNode), pointer :: &
num_homogMech
print'(/,a)', ' <<<+- homogenization_mech init -+>>>'
print'(/,a)', ' <<<+- homogenization:mechanical init -+>>>'
allocate(homogenization_dPdF(3,3,3,3,discretization_nIPs*discretization_Nelems), source=0.0_pReal)
homogenization_F0 = spread(math_I3,3,discretization_nIPs*discretization_Nelems) ! initialize to identity
@ -95,150 +92,145 @@ module subroutine mech_init(num_homog)
allocate(homogenization_P(3,3,discretization_nIPs*discretization_Nelems), source=0.0_pReal)
num_homogMech => num_homog%get('mech',defaultVal=emptyDict)
if (any(homogenization_type == HOMOGENIZATION_NONE_ID)) call mech_none_init
if (any(homogenization_type == HOMOGENIZATION_ISOSTRAIN_ID)) call mech_isostrain_init
if (any(homogenization_type == HOMOGENIZATION_RGC_ID)) call mech_RGC_init(num_homogMech)
if (any(homogenization_type == HOMOGENIZATION_NONE_ID)) call mechanical_pass_init
if (any(homogenization_type == HOMOGENIZATION_ISOSTRAIN_ID)) call mechanical_isostrain_init
if (any(homogenization_type == HOMOGENIZATION_RGC_ID)) call mechanical_RGC_init(num_homogMech)
end subroutine mech_init
end subroutine mechanical_init
!--------------------------------------------------------------------------------------------------
!> @brief Partition F onto the individual constituents.
!--------------------------------------------------------------------------------------------------
module subroutine mech_partition(subF,ip,el)
module subroutine mechanical_partition(subF,ce)
real(pReal), intent(in), dimension(3,3) :: &
subF
integer, intent(in) :: &
ip, & !< integration point
el !< element number
ce
chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el)))
integer :: co
real(pReal), dimension (3,3,homogenization_Nconstituents(material_homogenizationAt2(ce))) :: Fs
chosenHomogenization: select case(homogenization_type(material_homogenizationAt2(ce)))
case (HOMOGENIZATION_NONE_ID) chosenHomogenization
crystallite_F(1:3,1:3,1,ip,el) = subF
Fs(1:3,1:3,1) = subF
case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization
call mech_isostrain_partitionDeformation(&
crystallite_F(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), &
subF)
call mechanical_isostrain_partitionDeformation(Fs,subF)
case (HOMOGENIZATION_RGC_ID) chosenHomogenization
call mech_RGC_partitionDeformation(&
crystallite_F(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), &
subF,&
ip, &
el)
call mechanical_RGC_partitionDeformation(Fs,subF,ce)
end select chosenHomogenization
end subroutine mech_partition
do co = 1,homogenization_Nconstituents(material_homogenizationAt2(ce))
call phase_mechanical_setF(Fs(1:3,1:3,co),co,ce)
enddo
end subroutine mechanical_partition
!--------------------------------------------------------------------------------------------------
!> @brief Average P and dPdF from the individual constituents.
!--------------------------------------------------------------------------------------------------
module subroutine mech_homogenize(ip,el)
module subroutine mechanical_homogenize(dt,ce)
integer, intent(in) :: &
ip, & !< integration point
el !< element number
integer :: co,ce
real(pReal) :: dPdFs(3,3,3,3,homogenization_Nconstituents(material_homogenizationAt(el)))
real(pReal), intent(in) :: dt
integer, intent(in) :: ce
integer :: co
real(pReal) :: dPdFs(3,3,3,3,homogenization_Nconstituents(material_homogenizationAt2(ce)))
real(pReal) :: Ps(3,3,homogenization_Nconstituents(material_homogenizationAt2(ce)))
ce = (el-1)* discretization_nIPs + ip
chosenHomogenization: select case(homogenization_type(material_homogenizationAt(el)))
chosenHomogenization: select case(homogenization_type(material_homogenizationAt2(ce)))
case (HOMOGENIZATION_NONE_ID) chosenHomogenization
homogenization_P(1:3,1:3,ce) = crystallite_P(1:3,1:3,1,ip,el)
homogenization_dPdF(1:3,1:3,1:3,1:3,ce) = crystallite_stressTangent(1,ip,el)
homogenization_P(1:3,1:3,ce) = phase_mechanical_getP(1,ce)
homogenization_dPdF(1:3,1:3,1:3,1:3,ce) = phase_mechanical_dPdF(dt,1,ce)
case (HOMOGENIZATION_ISOSTRAIN_ID) chosenHomogenization
do co = 1, homogenization_Nconstituents(material_homogenizationAt(el))
dPdFs(:,:,:,:,co) = crystallite_stressTangent(co,ip,el)
do co = 1, homogenization_Nconstituents(material_homogenizationAt2(ce))
dPdFs(:,:,:,:,co) = phase_mechanical_dPdF(dt,co,ce)
Ps(:,:,co) = phase_mechanical_getP(co,ce)
enddo
call mech_isostrain_averageStressAndItsTangent(&
call mechanical_isostrain_averageStressAndItsTangent(&
homogenization_P(1:3,1:3,ce), &
homogenization_dPdF(1:3,1:3,1:3,1:3,ce),&
crystallite_P(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), &
dPdFs, &
homogenization_typeInstance(material_homogenizationAt(el)))
Ps,dPdFs, &
material_homogenizationAt2(ce))
case (HOMOGENIZATION_RGC_ID) chosenHomogenization
do co = 1, homogenization_Nconstituents(material_homogenizationAt(el))
dPdFs(:,:,:,:,co) = crystallite_stressTangent(co,ip,el)
do co = 1, homogenization_Nconstituents(material_homogenizationAt2(ce))
dPdFs(:,:,:,:,co) = phase_mechanical_dPdF(dt,co,ce)
Ps(:,:,co) = phase_mechanical_getP(co,ce)
enddo
call mech_RGC_averageStressAndItsTangent(&
call mechanical_RGC_averageStressAndItsTangent(&
homogenization_P(1:3,1:3,ce), &
homogenization_dPdF(1:3,1:3,1:3,1:3,ce),&
crystallite_P(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), &
dPdFs, &
homogenization_typeInstance(material_homogenizationAt(el)))
Ps,dPdFs, &
material_homogenizationAt2(ce))
end select chosenHomogenization
end subroutine mech_homogenize
end subroutine mechanical_homogenize
!--------------------------------------------------------------------------------------------------
!> @brief update the internal state of the homogenization scheme and tell whether "done" and
!> "happy" with result
!--------------------------------------------------------------------------------------------------
module function mech_updateState(subdt,subF,ip,el) result(doneAndHappy)
module function mechanical_updateState(subdt,subF,ce) result(doneAndHappy)
real(pReal), intent(in) :: &
subdt !< current time step
real(pReal), intent(in), dimension(3,3) :: &
subF
integer, intent(in) :: &
ip, & !< integration point
el !< element number
ce
logical, dimension(2) :: doneAndHappy
integer :: co
real(pReal) :: dPdFs(3,3,3,3,homogenization_Nconstituents(material_homogenizationAt(el)))
real(pReal) :: dPdFs(3,3,3,3,homogenization_Nconstituents(material_homogenizationAt2(ce)))
real(pReal) :: Fs(3,3,homogenization_Nconstituents(material_homogenizationAt2(ce)))
real(pReal) :: Ps(3,3,homogenization_Nconstituents(material_homogenizationAt2(ce)))
if (homogenization_type(material_homogenizationAt(el)) == HOMOGENIZATION_RGC_ID) then
do co = 1, homogenization_Nconstituents(material_homogenizationAt(el))
dPdFs(:,:,:,:,co) = crystallite_stressTangent(co,ip,el)
if (homogenization_type(material_homogenizationAt2(ce)) == HOMOGENIZATION_RGC_ID) then
do co = 1, homogenization_Nconstituents(material_homogenizationAt2(ce))
dPdFs(:,:,:,:,co) = phase_mechanical_dPdF(subdt,co,ce)
Fs(:,:,co) = phase_mechanical_getF(co,ce)
Ps(:,:,co) = phase_mechanical_getP(co,ce)
enddo
doneAndHappy = &
mech_RGC_updateState(crystallite_P(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), &
crystallite_F(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el), &
crystallite_partitionedF0(1:3,1:3,1:homogenization_Nconstituents(material_homogenizationAt(el)),ip,el),&
subF,&
subdt, &
dPdFs, &
ip, &
el)
doneAndHappy = mechanical_RGC_updateState(Ps,Fs,subF,subdt,dPdFs,ce)
else
doneAndHappy = .true.
endif
end function mech_updateState
end function mechanical_updateState
!--------------------------------------------------------------------------------------------------
!> @brief Write results to file.
!--------------------------------------------------------------------------------------------------
module subroutine mech_results(group_base,h)
use material, only: &
material_homogenization_type => homogenization_type
module subroutine mechanical_results(group_base,ho)
character(len=*), intent(in) :: group_base
integer, intent(in) :: h
integer, intent(in) :: ho
character(len=:), allocatable :: group
group = trim(group_base)//'/mech'
call results_closeGroup(results_addGroup(group))
select case(material_homogenization_type(h))
select case(homogenization_type(ho))
case(HOMOGENIZATION_rgc_ID)
call mech_RGC_results(homogenization_typeInstance(h),group)
call mechanical_RGC_results(ho,group)
end select
@ -249,7 +241,7 @@ module subroutine mech_results(group_base,h)
!call results_writeDataset(group,temp,'P',&
! '1st Piola-Kirchhoff stress','Pa')
end subroutine mech_results
end subroutine mechanical_results
end submodule homogenization_mech
end submodule mechanical

View File

@ -6,7 +6,7 @@
!> @brief Relaxed grain cluster (RGC) homogenization scheme
!> N_constituents is defined as p x q x r (cluster)
!--------------------------------------------------------------------------------------------------
submodule(homogenization:homogenization_mech) homogenization_mech_RGC
submodule(homogenization:mechanical) RGC
use rotations
use lattice
@ -24,9 +24,6 @@ submodule(homogenization:homogenization_mech) homogenization_mech_RGC
end type tParameters
type :: tRGCstate
real(pReal), pointer, dimension(:) :: &
work, &
penaltyEnergy
real(pReal), pointer, dimension(:,:) :: &
relaxationVector
end type tRGCstate
@ -74,14 +71,13 @@ contains
!--------------------------------------------------------------------------------------------------
!> @brief allocates all necessary fields, reads information from material configuration file
!--------------------------------------------------------------------------------------------------
module subroutine mech_RGC_init(num_homogMech)
module subroutine mechanical_RGC_init(num_homogMech)
class(tNode), pointer, intent(in) :: &
num_homogMech !< pointer to mechanical homogenization numerics data
integer :: &
Ninstances, &
h, &
ho, &
Nmaterialpoints, &
sizeState, nIntFaceTot
@ -91,10 +87,9 @@ module subroutine mech_RGC_init(num_homogMech)
homog, &
homogMech
print'(/,a)', ' <<<+- homogenization_mech_rgc init -+>>>'
print'(/,a)', ' <<<+- homogenization:mechanical:RGC init -+>>>'
Ninstances = count(homogenization_type == HOMOGENIZATION_RGC_ID)
print'(a,i2)', ' # instances: ',Ninstances; flush(IO_STDOUT)
print'(a,i2)', ' # instances: ',count(homogenization_type == HOMOGENIZATION_RGC_ID); flush(IO_STDOUT)
print*, 'Tjahjanto et al., International Journal of Material Forming 2(1):939942, 2009'
print*, 'https://doi.org/10.1007/s12289-009-0619-1'//IO_EOL
@ -104,10 +99,11 @@ module subroutine mech_RGC_init(num_homogMech)
allocate(param(Ninstances))
allocate(state(Ninstances))
allocate(state0(Ninstances))
allocate(dependentState(Ninstances))
material_homogenization => config_material%get('homogenization')
allocate(param(material_homogenization%length))
allocate(state(material_homogenization%length))
allocate(state0(material_homogenization%length))
allocate(dependentState(material_homogenization%length))
num_RGC => num_homogMech%get('RGC',defaultVal=emptyDict)
@ -140,15 +136,14 @@ module subroutine mech_RGC_init(num_homogMech)
if (num%volDiscrPow <= 0.0_pReal) call IO_error(301,ext_msg='volDiscrPw_RGC')
material_homogenization => config_material%get('homogenization')
do h = 1, size(homogenization_type)
if (homogenization_type(h) /= HOMOGENIZATION_RGC_ID) cycle
homog => material_homogenization%get(h)
do ho = 1, size(homogenization_type)
if (homogenization_type(ho) /= HOMOGENIZATION_RGC_ID) cycle
homog => material_homogenization%get(ho)
homogMech => homog%get('mechanics')
associate(prm => param(homogenization_typeInstance(h)), &
stt => state(homogenization_typeInstance(h)), &
st0 => state0(homogenization_typeInstance(h)), &
dst => dependentState(homogenization_typeInstance(h)))
associate(prm => param(ho), &
stt => state(ho), &
st0 => state0(ho), &
dst => dependentState(ho))
#if defined (__GFORTRAN__)
prm%output = output_asStrings(homogMech)
@ -157,8 +152,8 @@ module subroutine mech_RGC_init(num_homogMech)
#endif
prm%N_constituents = homogMech%get_asInts('cluster_size',requiredSize=3)
if (homogenization_Nconstituents(h) /= product(prm%N_constituents)) &
call IO_error(211,ext_msg='N_constituents (mech_RGC)')
if (homogenization_Nconstituents(ho) /= product(prm%N_constituents)) &
call IO_error(211,ext_msg='N_constituents (mechanical_RGC)')
prm%xi_alpha = homogMech%get_asFloat('xi_alpha')
prm%c_alpha = homogMech%get_asFloat('c_alpha')
@ -166,22 +161,18 @@ module subroutine mech_RGC_init(num_homogMech)
prm%D_alpha = homogMech%get_asFloats('D_alpha', requiredSize=3)
prm%a_g = homogMech%get_asFloats('a_g', requiredSize=3)
Nmaterialpoints = count(material_homogenizationAt == h)
Nmaterialpoints = count(material_homogenizationAt == ho)
nIntFaceTot = 3*( (prm%N_constituents(1)-1)*prm%N_constituents(2)*prm%N_constituents(3) &
+ prm%N_constituents(1)*(prm%N_constituents(2)-1)*prm%N_constituents(3) &
+ prm%N_constituents(1)*prm%N_constituents(2)*(prm%N_constituents(3)-1))
sizeState = nIntFaceTot &
+ size(['avg constitutive work ','average penalty energy'])
sizeState = nIntFaceTot
homogState(h)%sizeState = sizeState
allocate(homogState(h)%state0 (sizeState,Nmaterialpoints), source=0.0_pReal)
allocate(homogState(h)%subState0(sizeState,Nmaterialpoints), source=0.0_pReal)
allocate(homogState(h)%state (sizeState,Nmaterialpoints), source=0.0_pReal)
homogState(ho)%sizeState = sizeState
allocate(homogState(ho)%state0 (sizeState,Nmaterialpoints), source=0.0_pReal)
allocate(homogState(ho)%state (sizeState,Nmaterialpoints), source=0.0_pReal)
stt%relaxationVector => homogState(h)%state(1:nIntFaceTot,:)
st0%relaxationVector => homogState(h)%state0(1:nIntFaceTot,:)
stt%work => homogState(h)%state(nIntFaceTot+1,:)
stt%penaltyEnergy => homogState(h)%state(nIntFaceTot+2,:)
stt%relaxationVector => homogState(ho)%state(1:nIntFaceTot,:)
st0%relaxationVector => homogState(ho)%state0(1:nIntFaceTot,:)
allocate(dst%volumeDiscrepancy( Nmaterialpoints), source=0.0_pReal)
allocate(dst%relaxationRate_avg( Nmaterialpoints), source=0.0_pReal)
@ -190,35 +181,36 @@ module subroutine mech_RGC_init(num_homogMech)
!--------------------------------------------------------------------------------------------------
! assigning cluster orientations
dependentState(homogenization_typeInstance(h))%orientation = spread(eu2om(prm%a_g*inRad),3,Nmaterialpoints)
dependentState(ho)%orientation = spread(eu2om(prm%a_g*inRad),3,Nmaterialpoints)
!dst%orientation = spread(eu2om(prm%a_g*inRad),3,Nmaterialpoints) ifort version 18.0.1 crashes (for whatever reason)
end associate
enddo
end subroutine mech_RGC_init
end subroutine mechanical_RGC_init
!--------------------------------------------------------------------------------------------------
!> @brief partitions the deformation gradient onto the constituents
!--------------------------------------------------------------------------------------------------
module subroutine mech_RGC_partitionDeformation(F,avgF,instance,of)
module subroutine mechanical_RGC_partitionDeformation(F,avgF,ce)
real(pReal), dimension (:,:,:), intent(out) :: F !< partitioned F per grain
real(pReal), dimension (3,3), intent(in) :: avgF !< averaged F
integer, intent(in) :: &
instance, &
of
ce
real(pReal), dimension(3) :: aVect,nVect
integer, dimension(4) :: intFace
integer, dimension(3) :: iGrain3
integer :: iGrain,iFace,i,j
associate(prm => param(instance))
integer :: iGrain,iFace,i,j,ho,me
associate(prm => param(material_homogenizationAt2(ce)))
ho = material_homogenizationAt2(ce)
me = material_homogenizationMemberAt2(ce)
!--------------------------------------------------------------------------------------------------
! compute the deformation gradient of individual grains due to relaxations
F = 0.0_pReal
@ -226,8 +218,8 @@ module subroutine mech_RGC_partitionDeformation(F,avgF,instance,of)
iGrain3 = grain1to3(iGrain,prm%N_constituents)
do iFace = 1,6
intFace = getInterface(iFace,iGrain3) ! identifying 6 interfaces of each grain
aVect = relaxationVector(intFace,instance,of) ! get the relaxation vectors for each interface from global relaxation vector array
nVect = interfaceNormal(intFace,instance,of)
aVect = relaxationVector(intFace,ho,me) ! get the relaxation vectors for each interface from global relaxation vector array
nVect = interfaceNormal(intFace,ho,me)
forall (i=1:3,j=1:3) &
F(i,j,iGrain) = F(i,j,iGrain) + aVect(i)*nVect(j) ! calculating deformation relaxations due to interface relaxation
enddo
@ -236,29 +228,27 @@ module subroutine mech_RGC_partitionDeformation(F,avgF,instance,of)
end associate
end subroutine mech_RGC_partitionDeformation
end subroutine mechanical_RGC_partitionDeformation
!--------------------------------------------------------------------------------------------------
!> @brief update the internal state of the homogenization scheme and tell whether "done" and
! "happy" with result
!--------------------------------------------------------------------------------------------------
module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHappy)
module function mechanical_RGC_updateState(P,F,avgF,dt,dPdF,ce) result(doneAndHappy)
logical, dimension(2) :: doneAndHappy
real(pReal), dimension(:,:,:), intent(in) :: &
P,& !< partitioned stresses
F,& !< partitioned deformation gradients
F0 !< partitioned initial deformation gradients
F !< partitioned deformation gradients
real(pReal), dimension(:,:,:,:,:), intent(in) :: dPdF !< partitioned stiffnesses
real(pReal), dimension(3,3), intent(in) :: avgF !< average F
real(pReal), intent(in) :: dt !< time increment
integer, intent(in) :: &
ip, & !< integration point number
el !< element number
ce !< cell
integer, dimension(4) :: intFaceN,intFaceP,faceID
integer, dimension(3) :: nGDim,iGr3N,iGr3P
integer :: instance,iNum,i,j,nIntFaceTot,iGrN,iGrP,iMun,iFace,k,l,ipert,iGrain,nGrain, of
integer :: ho,iNum,i,j,nIntFaceTot,iGrN,iGrP,iMun,iFace,k,l,ipert,iGrain,nGrain, me
real(pReal), dimension(3,3,size(P,3)) :: R,pF,pR,D,pD
real(pReal), dimension(3,size(P,3)) :: NN,devNull
real(pReal), dimension(3) :: normP,normN,mornP,mornN
@ -272,10 +262,10 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
return
endif zeroTimeStep
instance = homogenization_typeInstance(material_homogenizationAt(el))
of = material_homogenizationMemberAt(ip,el)
ho = material_homogenizationAt2(ce)
associate(stt => state(instance), st0 => state0(instance), dst => dependentState(instance), prm => param(instance))
me = material_homogenizationMemberAt2(ce)
associate(stt => state(ho), st0 => state0(ho), dst => dependentState(ho), prm => param(ho))
!--------------------------------------------------------------------------------------------------
! get the dimension of the cluster (grains and interfaces)
@ -287,38 +277,38 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
!--------------------------------------------------------------------------------------------------
! allocate the size of the global relaxation arrays/jacobian matrices depending on the size of the cluster
allocate(resid(3*nIntFaceTot), source=0.0_pReal)
allocate(tract(nIntFaceTot,3), source=0.0_pReal)
relax = stt%relaxationVector(:,of)
drelax = stt%relaxationVector(:,of) - st0%relaxationVector(:,of)
allocate(resid(3*nIntFaceTot), source=0.0_pReal)
allocate(tract(nIntFaceTot,3), source=0.0_pReal)
relax = stt%relaxationVector(:,me)
drelax = stt%relaxationVector(:,me) - st0%relaxationVector(:,me)
!--------------------------------------------------------------------------------------------------
! computing interface mismatch and stress penalty tensor for all interfaces of all grains
call stressPenalty(R,NN,avgF,F,ip,el,instance,of)
call stressPenalty(R,NN,avgF,F,ho,me)
!--------------------------------------------------------------------------------------------------
! calculating volume discrepancy and stress penalty related to overall volume discrepancy
call volumePenalty(D,dst%volumeDiscrepancy(of),avgF,F,nGrain,instance,of)
call volumePenalty(D,dst%volumeDiscrepancy(me),avgF,F,nGrain)
!------------------------------------------------------------------------------------------------
! computing the residual stress from the balance of traction at all (interior) interfaces
do iNum = 1,nIntFaceTot
faceID = interface1to4(iNum,param(instance)%N_constituents) ! identifying the interface ID in local coordinate system (4-dimensional index)
faceID = interface1to4(iNum,param(ho)%N_constituents) ! 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 = grain3to1(iGr3N,param(instance)%N_constituents) ! translate the local grain ID into global coordinate system (1-dimensional index)
iGrN = grain3to1(iGr3N,param(ho)%N_constituents) ! translate the local grain ID into global coordinate system (1-dimensional index)
intFaceN = getInterface(2*faceID(1),iGr3N)
normN = interfaceNormal(intFaceN,instance,of)
normN = interfaceNormal(intFaceN,ho,me)
!--------------------------------------------------------------------------------------------------
! identify the right/up/front grain (+|P)
iGr3P = iGr3N
iGr3P(faceID(1)) = iGr3N(faceID(1))+1 ! identifying the grain ID in local coordinate system (3-dimensional index)
iGrP = grain3to1(iGr3P,param(instance)%N_constituents) ! translate the local grain ID into global coordinate system (1-dimensional index)
iGrP = grain3to1(iGr3P,param(ho)%N_constituents) ! translate the local grain ID into global coordinate system (1-dimensional index)
intFaceP = getInterface(2*faceID(1)-1,iGr3P)
normP = interfaceNormal(intFaceP,instance,of)
normP = interfaceNormal(intFaceP,ho,me)
!--------------------------------------------------------------------------------------------------
! compute the residual of traction at the interface (in local system, 4-dimensional index)
@ -346,20 +336,9 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
if (residMax < num%rtol*stresMax .or. residMax < num%atol) then
doneAndHappy = .true.
!--------------------------------------------------------------------------------------------------
! compute/update the state for postResult, i.e., all energy densities computed by time-integration
do iGrain = 1,product(prm%N_constituents)
do i = 1,3;do j = 1,3
stt%work(of) = stt%work(of) &
+ P(i,j,iGrain)*(F(i,j,iGrain) - F0(i,j,iGrain))/real(nGrain,pReal)
stt%penaltyEnergy(of) = stt%penaltyEnergy(of) &
+ R(i,j,iGrain)*(F(i,j,iGrain) - F0(i,j,iGrain))/real(nGrain,pReal)
enddo; enddo
enddo
dst%mismatch(1:3,of) = sum(NN,2)/real(nGrain,pReal)
dst%relaxationRate_avg(of) = sum(abs(drelax))/dt/real(3*nIntFaceTot,pReal)
dst%relaxationRate_max(of) = maxval(abs(drelax))/dt
dst%mismatch(1:3,me) = sum(NN,2)/real(nGrain,pReal)
dst%relaxationRate_avg(me) = sum(abs(drelax))/dt/real(3*nIntFaceTot,pReal)
dst%relaxationRate_max(me) = maxval(abs(drelax))/dt
return
@ -378,18 +357,18 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
! ... 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,nIntFaceTot
faceID = interface1to4(iNum,param(instance)%N_constituents) ! assembling of local dPdF into global Jacobian matrix
faceID = interface1to4(iNum,param(ho)%N_constituents) ! 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 = grain3to1(iGr3N,param(instance)%N_constituents) ! translate into global grain ID
iGrN = grain3to1(iGr3N,param(ho)%N_constituents) ! translate into global grain ID
intFaceN = getInterface(2*faceID(1),iGr3N) ! identifying the connecting interface in local coordinate system
normN = interfaceNormal(intFaceN,instance,of)
normN = interfaceNormal(intFaceN,ho,me)
do iFace = 1,6
intFaceN = getInterface(iFace,iGr3N) ! identifying all interfaces that influence relaxation of the above interface
mornN = interfaceNormal(intFaceN,instance,of)
iMun = interface4to1(intFaceN,param(instance)%N_constituents) ! translate the interfaces ID into local 4-dimensional index
mornN = interfaceNormal(intFaceN,ho,me)
iMun = interface4to1(intFaceN,param(ho)%N_constituents) ! translate the interfaces ID into local 4-dimensional index
if (iMun > 0) then ! get the corresponding tangent
do i=1,3; do j=1,3; do k=1,3; do l=1,3
smatrix(3*(iNum-1)+i,3*(iMun-1)+j) = smatrix(3*(iNum-1)+i,3*(iMun-1)+j) &
@ -404,13 +383,13 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
! identify the right/up/front grain (+|P)
iGr3P = iGr3N
iGr3P(faceID(1)) = iGr3N(faceID(1))+1 ! identifying the grain ID in local coordinate sytem
iGrP = grain3to1(iGr3P,param(instance)%N_constituents) ! translate into global grain ID
iGrP = grain3to1(iGr3P,param(ho)%N_constituents) ! translate into global grain ID
intFaceP = getInterface(2*faceID(1)-1,iGr3P) ! identifying the connecting interface in local coordinate system
normP = interfaceNormal(intFaceP,instance,of)
normP = interfaceNormal(intFaceP,ho,me)
do iFace = 1,6
intFaceP = getInterface(iFace,iGr3P) ! identifying all interfaces that influence relaxation of the above interface
mornP = interfaceNormal(intFaceP,instance,of)
iMun = interface4to1(intFaceP,param(instance)%N_constituents) ! translate the interfaces ID into local 4-dimensional index
mornP = interfaceNormal(intFaceP,ho,me)
iMun = interface4to1(intFaceP,param(ho)%N_constituents) ! translate the interfaces ID into local 4-dimensional index
if (iMun > 0) then ! get the corresponding tangent
do i=1,3; do j=1,3; do k=1,3; do l=1,3
smatrix(3*(iNum-1)+i,3*(iMun-1)+j) = smatrix(3*(iNum-1)+i,3*(iMun-1)+j) &
@ -430,31 +409,31 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
do ipert = 1,3*nIntFaceTot
p_relax = relax
p_relax(ipert) = relax(ipert) + num%pPert ! perturb the relaxation vector
stt%relaxationVector(:,of) = p_relax
call grainDeformation(pF,avgF,instance,of) ! rain deformation from perturbed state
call stressPenalty(pR,DevNull, avgF,pF,ip,el,instance,of) ! stress penalty due to interface mismatch from perturbed state
call volumePenalty(pD,devNull(1,1), avgF,pF,nGrain,instance,of) ! stress penalty due to volume discrepancy from perturbed state
stt%relaxationVector(:,me) = p_relax
call grainDeformation(pF,avgF,ho,me) ! rain deformation from perturbed state
call stressPenalty(pR,DevNull, avgF,pF,ho,me) ! stress penalty due to interface mismatch from perturbed state
call volumePenalty(pD,devNull(1,1), avgF,pF,nGrain) ! 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,nIntFaceTot
faceID = interface1to4(iNum,param(instance)%N_constituents) ! identifying the interface ID in local coordinate system (4-dimensional index)
faceID = interface1to4(iNum,param(ho)%N_constituents) ! identifying the interface ID in local coordinate system (4-dimensional index)
!--------------------------------------------------------------------------------------------------
! identify the left/bottom/back grain (-|N)
iGr3N = faceID(2:4) ! identify the grain ID in local coordinate system (3-dimensional index)
iGrN = grain3to1(iGr3N,param(instance)%N_constituents) ! translate the local grain ID into global coordinate system (1-dimensional index)
iGrN = grain3to1(iGr3N,param(ho)%N_constituents) ! translate the local grain ID into global coordinate system (1-dimensional index)
intFaceN = getInterface(2*faceID(1),iGr3N) ! identify the interface ID of the grain
normN = interfaceNormal(intFaceN,instance,of)
normN = interfaceNormal(intFaceN,ho,me)
!--------------------------------------------------------------------------------------------------
! identify the right/up/front grain (+|P)
iGr3P = iGr3N
iGr3P(faceID(1)) = iGr3N(faceID(1))+1 ! identify the grain ID in local coordinate system (3-dimensional index)
iGrP = grain3to1(iGr3P,param(instance)%N_constituents) ! translate the local grain ID into global coordinate system (1-dimensional index)
iGrP = grain3to1(iGr3P,param(ho)%N_constituents) ! translate the local grain ID into global coordinate system (1-dimensional index)
intFaceP = getInterface(2*faceID(1)-1,iGr3P) ! identify the interface ID of the grain
normP = interfaceNormal(intFaceP,instance,of)
normP = interfaceNormal(intFaceP,ho,me)
!--------------------------------------------------------------------------------------------------
! compute the residual stress (contribution of mismatch and volume penalties) from perturbed state
@ -494,11 +473,11 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
do i = 1,3*nIntFaceTot;do j = 1,3*nIntFaceTot
drelax(i) = drelax(i) - jnverse(i,j)*resid(j) ! Calculate the correction for the state variable
enddo; enddo
stt%relaxationVector(:,of) = relax + drelax ! Updateing the state variable for the next iteration
stt%relaxationVector(:,me) = relax + drelax ! Updateing the state variable for the next iteration
if (any(abs(drelax) > num%maxdRelax)) then ! Forcing cutback when the incremental change of relaxation vector becomes too large
doneAndHappy = [.true.,.false.]
!$OMP CRITICAL (write2out)
print'(a,i3,a,i3,a)',' RGC_updateState: ip ',ip,' | el ',el,' enforces cutback'
print'(a,i3,a,i3,a)',' RGC_updateState: enforces cutback'
print'(a,e15.8)',' due to large relaxation change = ',maxval(abs(drelax))
flush(IO_STDOUT)
!$OMP END CRITICAL (write2out)
@ -510,27 +489,26 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
!------------------------------------------------------------------------------------------------
!> @brief calculate stress-like penalty due to deformation mismatch
!------------------------------------------------------------------------------------------------
subroutine stressPenalty(rPen,nMis,avgF,fDef,ip,el,instance,of)
subroutine stressPenalty(rPen,nMis,avgF,fDef,ho,me)
real(pReal), dimension (:,:,:), intent(out) :: rPen !< stress-like penalty
real(pReal), dimension (:,:), intent(out) :: nMis !< total amount of mismatch
real(pReal), dimension (:,:,:), intent(in) :: fDef !< deformation gradients
real(pReal), dimension (3,3), intent(in) :: avgF !< initial effective stretch tensor
integer, intent(in) :: ip,el,instance,of
integer, intent(in) :: ho, me
integer, dimension (4) :: intFace
integer, dimension (3) :: iGrain3,iGNghb3,nGDim
real(pReal), dimension (3,3) :: gDef,nDef
real(pReal), dimension (3) :: nVect,surfCorr
real(pReal), dimension (2) :: Gmoduli
integer :: iGrain,iGNghb,iFace,i,j,k,l
real(pReal) :: muGrain,muGNghb,nDefNorm
real(pReal), parameter :: &
nDefToler = 1.0e-10_pReal, &
b = 2.5e-10_pReal ! Length of Burgers vector
nGDim = param(instance)%N_constituents
nGDim = param(ho)%N_constituents
rPen = 0.0_pReal
nMis = 0.0_pReal
@ -538,27 +516,26 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
! get the correction factor the modulus of penalty stress representing the evolution of area of
! the interfaces due to deformations
surfCorr = surfaceCorrection(avgF,instance,of)
associate(prm => param(instance))
surfCorr = surfaceCorrection(avgF,ho,me)
associate(prm => param(ho))
!-----------------------------------------------------------------------------------------------
! computing the mismatch and penalty stress tensor of all grains
grainLoop: do iGrain = 1,product(prm%N_constituents)
muGrain = equivalentMu(iGrain,ip,el)
muGrain = equivalentMu(iGrain,ce)
iGrain3 = grain1to3(iGrain,prm%N_constituents) ! get the grain ID in local 3-dimensional index (x,y,z)-position
interfaceLoop: do iFace = 1,6
intFace = getInterface(iFace,iGrain3) ! get the 4-dimensional index of the interface in local numbering system of the grain
nVect = interfaceNormal(intFace,instance,of)
nVect = interfaceNormal(intFace,ho,me)
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))
where(iGNghb3 < 1) iGNghb3 = nGDim
where(iGNghb3 >nGDim) iGNghb3 = 1
iGNghb = grain3to1(iGNghb3,prm%N_constituents) ! get the ID of the neighboring grain
muGNghb = equivalentMu(iGNghb,ip,el)
muGNghb = equivalentMu(iGNghb,ce)
gDef = 0.5_pReal*(fDef(1:3,1:3,iGNghb) - fDef(1:3,1:3,iGrain)) ! difference/jump in deformation gradeint across the neighbor
!-------------------------------------------------------------------------------------------
@ -597,7 +574,7 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
!------------------------------------------------------------------------------------------------
!> @brief calculate stress-like penalty due to volume discrepancy
!------------------------------------------------------------------------------------------------
subroutine volumePenalty(vPen,vDiscrep,fAvg,fDef,nGrain,instance,of)
subroutine volumePenalty(vPen,vDiscrep,fAvg,fDef,nGrain)
real(pReal), dimension (:,:,:), intent(out) :: vPen ! stress-like penalty due to volume
real(pReal), intent(out) :: vDiscrep ! total volume discrepancy
@ -605,9 +582,7 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
real(pReal), dimension (:,:,:), intent(in) :: fDef ! deformation gradients
real(pReal), dimension (3,3), intent(in) :: fAvg ! overall deformation gradient
integer, intent(in) :: &
Ngrain, &
instance, &
of
Ngrain
real(pReal), dimension(size(vPen,3)) :: gVol
integer :: i
@ -637,14 +612,14 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
!> @brief compute the correction factor accouted for surface evolution (area change) due to
! deformation
!--------------------------------------------------------------------------------------------------
function surfaceCorrection(avgF,instance,of)
function surfaceCorrection(avgF,ho,me)
real(pReal), dimension(3) :: surfaceCorrection
real(pReal), dimension(3,3), intent(in) :: avgF !< average F
integer, intent(in) :: &
instance, &
of
ho, &
me
real(pReal), dimension(3,3) :: invC
real(pReal), dimension(3) :: nVect
real(pReal) :: detF
@ -655,7 +630,7 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
surfaceCorrection = 0.0_pReal
do iBase = 1,3
nVect = interfaceNormal([iBase,1,1,1],instance,of)
nVect = interfaceNormal([iBase,1,1,1],ho,me)
do i = 1,3; do j = 1,3
surfaceCorrection(iBase) = surfaceCorrection(iBase) + invC(i,j)*nVect(i)*nVect(j) ! compute the component of (the inverse of) the stretch in the direction of the normal
enddo; enddo
@ -668,15 +643,17 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
!-------------------------------------------------------------------------------------------------
!> @brief compute the equivalent shear and bulk moduli from the elasticity tensor
!-------------------------------------------------------------------------------------------------
real(pReal) function equivalentMu(grainID,ip,el)
real(pReal) function equivalentMu(grainID,ce)
integer, intent(in) :: &
grainID,&
ip, & !< integration point number
el !< element number
ce
real(pReal), dimension(6,6) :: C
equivalentMu = lattice_equivalent_mu(constitutive_homogenizedC(grainID,ip,el),'voigt')
C = phase_homogenizedC(material_phaseAt2(grainID,ce),material_phaseMemberAt2(grainID,ce))
equivalentMu = lattice_equivalent_mu(C,'voigt')
end function equivalentMu
@ -685,14 +662,14 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
!> @brief calculating the grain deformation gradient (the same with
! homogenization_RGC_partitionDeformation, but used only for perturbation scheme)
!-------------------------------------------------------------------------------------------------
subroutine grainDeformation(F, avgF, instance, of)
subroutine grainDeformation(F, avgF, ho, me)
real(pReal), dimension(:,:,:), intent(out) :: F !< partitioned F per grain
real(pReal), dimension(:,:), intent(in) :: avgF !< averaged F
integer, intent(in) :: &
instance, &
of
ho, &
me
real(pReal), dimension(3) :: aVect,nVect
integer, dimension(4) :: intFace
@ -702,15 +679,15 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
!-----------------------------------------------------------------------------------------------
! compute the deformation gradient of individual grains due to relaxations
associate(prm => param(instance))
associate (prm => param(ho))
F = 0.0_pReal
do iGrain = 1,product(prm%N_constituents)
iGrain3 = grain1to3(iGrain,prm%N_constituents)
do iFace = 1,6
intFace = getInterface(iFace,iGrain3)
aVect = relaxationVector(intFace,instance,of)
nVect = interfaceNormal(intFace,instance,of)
aVect = relaxationVector(intFace,ho,me)
nVect = interfaceNormal(intFace,ho,me)
forall (i=1:3,j=1:3) &
F(i,j,iGrain) = F(i,j,iGrain) + aVect(i)*nVect(j) ! effective relaxations
enddo
@ -721,49 +698,43 @@ module function mech_RGC_updateState(P,F,F0,avgF,dt,dPdF,ip,el) result(doneAndHa
end subroutine grainDeformation
end function mech_RGC_updateState
end function mechanical_RGC_updateState
!--------------------------------------------------------------------------------------------------
!> @brief derive average stress and stiffness from constituent quantities
!--------------------------------------------------------------------------------------------------
module subroutine mech_RGC_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,instance)
module subroutine mechanical_RGC_averageStressAndItsTangent(avgP,dAvgPdAvgF,P,dPdF,ho)
real(pReal), dimension (3,3), intent(out) :: avgP !< average stress at material point
real(pReal), dimension (3,3,3,3), intent(out) :: dAvgPdAvgF !< average stiffness at material point
real(pReal), dimension (:,:,:), intent(in) :: P !< partitioned stresses
real(pReal), dimension (:,:,:,:,:), intent(in) :: dPdF !< partitioned stiffnesses
integer, intent(in) :: instance
integer, intent(in) :: ho
avgP = sum(P,3) /real(product(param(instance)%N_constituents),pReal)
dAvgPdAvgF = sum(dPdF,5)/real(product(param(instance)%N_constituents),pReal)
avgP = sum(P,3) /real(product(param(ho)%N_constituents),pReal)
dAvgPdAvgF = sum(dPdF,5)/real(product(param(ho)%N_constituents),pReal)
end subroutine mech_RGC_averageStressAndItsTangent
end subroutine mechanical_RGC_averageStressAndItsTangent
!--------------------------------------------------------------------------------------------------
!> @brief writes results to HDF5 output file
!--------------------------------------------------------------------------------------------------
module subroutine mech_RGC_results(instance,group)
module subroutine mechanical_RGC_results(ho,group)
integer, intent(in) :: instance
integer, intent(in) :: ho
character(len=*), intent(in) :: group
integer :: o
associate(stt => state(instance), dst => dependentState(instance), prm => param(instance))
associate(stt => state(ho), dst => dependentState(ho), prm => param(ho))
outputsLoop: do o = 1,size(prm%output)
select case(trim(prm%output(o)))
case('W')
call results_writeDataset(group,stt%work,trim(prm%output(o)), &
'work density','J/m³')
case('M')
call results_writeDataset(group,dst%mismatch,trim(prm%output(o)), &
'average mismatch tensor','1')
case('R')
call results_writeDataset(group,stt%penaltyEnergy,trim(prm%output(o)), &
'mismatch penalty density','J/m³')
case('Delta_V')
call results_writeDataset(group,dst%volumeDiscrepancy,trim(prm%output(o)), &
'volume discrepancy','m³')
@ -777,17 +748,17 @@ module subroutine mech_RGC_results(instance,group)
enddo outputsLoop
end associate
end subroutine mech_RGC_results
end subroutine mechanical_RGC_results
!--------------------------------------------------------------------------------------------------
!> @brief collect relaxation vectors of an interface
!--------------------------------------------------------------------------------------------------
pure function relaxationVector(intFace,instance,of)
pure function relaxationVector(intFace,ho,me)
real(pReal), dimension (3) :: relaxationVector
integer, intent(in) :: instance,of
integer, intent(in) :: ho,me
integer, dimension(4), intent(in) :: intFace !< set of interface ID in 4D array (normal and position)
integer :: iNum
@ -795,29 +766,35 @@ pure function relaxationVector(intFace,instance,of)
!--------------------------------------------------------------------------------------------------
! collect the interface relaxation vector from the global state array
iNum = interface4to1(intFace,param(instance)%N_constituents) ! identify the position of the interface in global state array
associate (prm => param(ho), &
stt => state(ho))
iNum = interface4to1(intFace,prm%N_constituents) ! identify the position of the interface in global state array
if (iNum > 0) then
relaxationVector = state(instance)%relaxationVector((3*iNum-2):(3*iNum),of)
relaxationVector = stt%relaxationVector((3*iNum-2):(3*iNum),me)
else
relaxationVector = 0.0_pReal
endif
end associate
end function relaxationVector
!--------------------------------------------------------------------------------------------------
!> @brief identify the normal of an interface
!--------------------------------------------------------------------------------------------------
pure function interfaceNormal(intFace,instance,of)
pure function interfaceNormal(intFace,ho,me)
real(pReal), dimension(3) :: interfaceNormal
integer, dimension(4), intent(in) :: intFace !< interface ID in 4D array (normal and position)
integer, intent(in) :: &
instance, &
of
ho, &
me
integer :: nPos
associate (dst => dependentState(ho))
!--------------------------------------------------------------------------------------------------
! get the normal of the interface, identified from the value of intFace(1)
@ -825,7 +802,9 @@ pure function interfaceNormal(intFace,instance,of)
nPos = abs(intFace(1)) ! identify the position of the interface in global state array
interfaceNormal(nPos) = real(intFace(1)/abs(intFace(1)),pReal) ! get the normal vector w.r.t. cluster axis
interfaceNormal = matmul(dependentState(instance)%orientation(1:3,1:3,of),interfaceNormal) ! map the normal vector into sample coordinate system (basis)
interfaceNormal = matmul(dst%orientation(1:3,1:3,me),interfaceNormal) ! map the normal vector into sample coordinate system (basis)
end associate
end function interfaceNormal
@ -970,4 +949,4 @@ pure function interface1to4(iFace1D, nGDim)
end function interface1to4
end submodule homogenization_mech_RGC
end submodule RGC

Some files were not shown because too many files have changed in this diff Show More