DAMASK_EICMD/src/homogenization_mechanical_R...

928 lines
49 KiB
Fortran
Raw Normal View History

!--------------------------------------------------------------------------------------------------
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
!> @author Denny Tjahjanto, Max-Planck-Institut für Eisenforschung GmbH
!> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH
!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH
!> @brief Relaxed grain cluster (RGC) homogenization scheme
2020-09-23 05:03:19 +05:30
!> N_constituents is defined as p x q x r (cluster)
!--------------------------------------------------------------------------------------------------
2021-02-13 23:27:41 +05:30
submodule(homogenization:mechanical) RGC
use rotations
2023-07-15 23:58:57 +05:30
use crystal
2018-08-28 16:27:22 +05:30
2019-06-15 21:57:38 +05:30
type :: tParameters
integer, dimension(:), allocatable :: &
2020-09-23 05:03:19 +05:30
N_constituents
real(pREAL) :: &
2020-09-23 05:03:19 +05:30
xi_alpha, &
c_Alpha
real(pREAL), dimension(:), allocatable :: &
2020-09-23 05:03:19 +05:30
D_alpha, &
a_g
2023-06-04 10:47:38 +05:30
character(len=pSTRLEN), allocatable, dimension(:) :: &
2020-02-15 03:51:58 +05:30
output
2019-06-15 21:57:38 +05:30
end type tParameters
2019-06-15 21:57:38 +05:30
type :: tRGCstate
real(pREAL), pointer, dimension(:,:) :: &
2019-06-15 21:57:38 +05:30
relaxationVector
end type tRGCstate
2019-06-15 21:57:38 +05:30
type :: tRGCdependentState
real(pREAL), allocatable, dimension(:) :: &
2019-06-15 21:57:38 +05:30
volumeDiscrepancy, &
relaxationRate_avg, &
relaxationRate_max
real(pREAL), allocatable, dimension(:,:) :: &
2019-06-15 21:57:38 +05:30
mismatch
real(pREAL), allocatable, dimension(:,:,:) :: &
2019-06-15 21:57:38 +05:30
orientation
end type tRGCdependentState
2020-03-17 05:09:32 +05:30
type :: tNumerics_RGC
real(pREAL) :: &
2020-06-26 15:52:33 +05:30
atol, & !< absolute tolerance of RGC residuum
rtol, & !< relative tolerance of RGC residuum
absMax, & !< absolute maximum of RGC residuum
relMax, & !< relative maximum of RGC residuum
pPert, & !< perturbation for computing RGC penalty tangent
xSmoo, & !< RGC penalty smoothing parameter (hyperbolic tangent)
viscPower, & !< power (sensitivity rate) of numerical viscosity in RGC scheme, Default 1.0e0: Newton viscosity (linear model)
viscModus, & !< stress modulus of RGC numerical viscosity, Default 0.0e0: No viscosity is applied
refRelaxRate, & !< reference relaxation rate in RGC viscosity
maxdRelax, & !< threshold of maximum relaxation vector increment (if exceed this then cutback)
maxVolDiscr, & !< threshold of maximum volume discrepancy allowed
volDiscrMod, & !< stiffness of RGC volume discrepancy (zero = without volume discrepancy constraint)
volDiscrPow !< powerlaw penalty for volume discrepancy
2020-03-17 05:09:32 +05:30
end type tNumerics_RGC
2019-06-15 21:57:38 +05:30
type(tparameters), dimension(:), allocatable :: &
param
type(tRGCstate), dimension(:), allocatable :: &
state, &
state0
type(tRGCdependentState), dimension(:), allocatable :: &
dependentState
2020-03-17 05:09:32 +05:30
type(tNumerics_RGC) :: &
num ! numerics parameters. Better name?
2018-11-04 02:06:49 +05:30
contains
!--------------------------------------------------------------------------------------------------
2018-04-17 18:12:04 +05:30
!> @brief allocates all necessary fields, reads information from material configuration file
!--------------------------------------------------------------------------------------------------
module subroutine RGC_init()
2020-07-03 20:15:11 +05:30
2019-06-15 21:57:38 +05:30
integer :: &
2021-02-26 02:12:40 +05:30
ho, &
2021-05-23 13:40:25 +05:30
Nmembers, &
2020-07-02 01:50:22 +05:30
sizeState, nIntFaceTot
2020-09-07 16:50:00 +05:30
class(tDict), pointer :: &
num_homogenization, &
num_mechanical, &
2020-08-15 19:32:10 +05:30
num_RGC, & ! pointer to RGC numerics data
material_homogenization, &
homog, &
homogMech
print'(/,1x,a)', '<<<+- homogenization:mechanical:RGC init -+>>>'
2022-02-24 16:39:47 +05:30
print'(/,a,i0)', ' # homogenizations: ',count(mechanical_type == MECHANICAL_RGC_ID)
2021-04-11 15:48:26 +05:30
flush(IO_STDOUT)
2020-09-18 02:27:56 +05:30
print'(/,1x,a)', 'D.D. Tjahjanto et al., International Journal of Material Forming 2(1):939942, 2009'
print'( 1x,a)', 'https://doi.org/10.1007/s12289-009-0619-1'//IO_EOL
2020-09-18 02:27:56 +05:30
print'(/,1x,a)', 'D.D. Tjahjanto et al., Modelling and Simulation in Materials Science and Engineering 18:015006, 2010'
print'( 1x,a)', 'https://doi.org/10.1088/0965-0393/18/1/015006'//IO_EOL
material_homogenization => config_material%get_dict('homogenization')
allocate(param(material_homogenization%length))
allocate(state(material_homogenization%length))
allocate(state0(material_homogenization%length))
allocate(dependentState(material_homogenization%length))
2020-09-07 16:50:00 +05:30
num_homogenization => config_numerics%get_dict('homogenization',defaultVal=emptyDict)
num_mechanical => num_homogenization%get_dict('mechanical',defaultVal=emptyDict)
num_RGC => num_mechanical%get_dict('RGC',defaultVal=emptyDict)
2020-06-29 18:39:13 +05:30
2023-08-01 14:19:43 +05:30
num%atol = num_RGC%get_asReal('eps_abs_P', defaultVal=1.0e+4_pREAL)
num%rtol = num_RGC%get_asReal('eps_rel_P', defaultVal=1.0e-3_pREAL)
num%absMax = num_RGC%get_asReal('eps_abs_max', defaultVal=1.0e+10_pREAL)
num%relMax = num_RGC%get_asReal('eps_rel_max', defaultVal=1.0e+2_pREAL)
num%pPert = num_RGC%get_asReal('Delta_a', defaultVal=1.0e-7_pREAL)
num%xSmoo = num_RGC%get_asReal('relevant_mismatch', defaultVal=1.0e-5_pREAL)
num%viscPower = num_RGC%get_asReal('viscosity_exponent', defaultVal=1.0e+0_pREAL)
num%viscModus = num_RGC%get_asReal('viscosity_modulus', defaultVal=0.0e+0_pREAL)
num%refRelaxRate = num_RGC%get_asReal('dot_a_ref', defaultVal=1.0e-3_pREAL)
num%maxdRelax = num_RGC%get_asReal('dot_a_max', defaultVal=1.0e+0_pREAL)
num%maxVolDiscr = num_RGC%get_asReal('Delta_V_max', defaultVal=1.0e-5_pREAL)
2023-08-01 20:12:45 +05:30
num%volDiscrMod = num_RGC%get_asReal('Delta_V_modulus', defaultVal=1.0e+12_pREAL)
num%volDiscrPow = num_RGC%get_asReal('Delta_V_exponent', defaultVal=5.0_pREAL)
2023-08-01 14:19:43 +05:30
if (num%atol <= 0.0_pREAL) call IO_error(301,ext_msg='eps_abs_P')
if (num%rtol <= 0.0_pREAL) call IO_error(301,ext_msg='eps_rel_P')
if (num%absMax <= 0.0_pREAL) call IO_error(301,ext_msg='eps_abs_max')
if (num%relMax <= 0.0_pREAL) call IO_error(301,ext_msg='eps_rel_max')
if (num%pPert <= 0.0_pREAL) call IO_error(301,ext_msg='Delta_a')
if (num%xSmoo <= 0.0_pREAL) call IO_error(301,ext_msg='relevant_mismatch')
if (num%viscPower < 0.0_pREAL) call IO_error(301,ext_msg='viscosity_exponent')
if (num%viscModus < 0.0_pREAL) call IO_error(301,ext_msg='viscosity_modulus')
if (num%refRelaxRate <= 0.0_pREAL) call IO_error(301,ext_msg='dot_a_ref')
if (num%maxdRelax <= 0.0_pREAL) call IO_error(301,ext_msg='dot_a_max')
if (num%maxVolDiscr <= 0.0_pREAL) call IO_error(301,ext_msg='Delta_V_max')
2023-08-01 20:12:45 +05:30
if (num%volDiscrMod < 0.0_pREAL) call IO_error(301,ext_msg='Delta_V_modulus')
if (num%volDiscrPow <= 0.0_pREAL) call IO_error(301,ext_msg='Delta_V_exponent')
2020-08-15 19:32:10 +05:30
2022-02-24 16:39:47 +05:30
do ho = 1, size(mechanical_type)
if (mechanical_type(ho) /= MECHANICAL_RGC_ID) cycle
homog => material_homogenization%get_dict(ho)
homogMech => homog%get_dict('mechanical')
2021-02-26 02:12:40 +05:30
associate(prm => param(ho), &
stt => state(ho), &
st0 => state0(ho), &
dst => dependentState(ho))
2020-08-15 19:32:10 +05:30
#if defined (__GFORTRAN__)
2023-06-04 10:47:38 +05:30
prm%output = output_as1dStr(homogMech)
2020-08-15 19:32:10 +05:30
#else
2023-06-04 10:47:38 +05:30
prm%output = homogMech%get_as1dStr('output',defaultVal=emptyStrArray)
2020-08-15 19:32:10 +05:30
#endif
2021-03-11 22:30:07 +05:30
prm%N_constituents = homogMech%get_as1dInt('cluster_size',requiredSize=3)
2021-02-26 02:12:40 +05:30
if (homogenization_Nconstituents(ho) /= product(prm%N_constituents)) &
call IO_error(211,ext_msg='N_constituents (RGC)')
prm%xi_alpha = homogMech%get_asReal('xi_alpha')
prm%c_alpha = homogMech%get_asReal('c_alpha')
prm%D_alpha = homogMech%get_as1dReal('D_alpha', requiredSize=3)
prm%a_g = homogMech%get_as1dReal('a_g', requiredSize=3)
2020-02-15 03:51:58 +05:30
2023-01-23 13:01:59 +05:30
Nmembers = count(material_ID_homogenization == ho)
2020-09-23 05:03:19 +05:30
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
2021-02-26 02:12:40 +05:30
homogState(ho)%sizeState = sizeState
allocate(homogState(ho)%state0 (sizeState,Nmembers), source=0.0_pREAL)
allocate(homogState(ho)%state (sizeState,Nmembers), source=0.0_pREAL)
stt%relaxationVector => homogState(ho)%state(1:nIntFaceTot,:)
st0%relaxationVector => homogState(ho)%state0(1:nIntFaceTot,:)
allocate(dst%volumeDiscrepancy( Nmembers), source=0.0_pREAL)
allocate(dst%relaxationRate_avg( Nmembers), source=0.0_pREAL)
allocate(dst%relaxationRate_max( Nmembers), source=0.0_pREAL)
allocate(dst%mismatch( 3,Nmembers), source=0.0_pREAL)
2018-11-04 02:06:49 +05:30
!--------------------------------------------------------------------------------------------------
2019-01-13 02:34:03 +05:30
! assigning cluster orientations
2021-05-23 13:40:25 +05:30
dependentState(ho)%orientation = spread(eu2om(prm%a_g*inRad),3,Nmembers)
!dst%orientation = spread(eu2om(prm%a_g*inRad),3,Nmembers) ifort version 18.0.1 crashes (for whatever reason)
2019-06-15 21:57:38 +05:30
end associate
end do
end subroutine RGC_init
!--------------------------------------------------------------------------------------------------
!> @brief partitions the deformation gradient onto the constituents
!--------------------------------------------------------------------------------------------------
module subroutine 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
2019-06-15 21:57:38 +05:30
integer, intent(in) :: &
2021-02-15 23:13:51 +05:30
ce
2020-07-02 01:50:22 +05:30
real(pREAL), dimension(3) :: aVect,nVect
2019-06-15 21:57:38 +05:30
integer, dimension(4) :: intFace
integer, dimension(3) :: iGrain3
2021-04-06 15:08:44 +05:30
integer :: iGrain,iFace,i,j,ho,en
2023-01-23 13:01:59 +05:30
associate(prm => param(material_ID_homogenization(ce)))
2021-04-11 15:48:26 +05:30
2023-01-23 13:01:59 +05:30
ho = material_ID_homogenization(ce)
en = material_entry_homogenization(ce)
!--------------------------------------------------------------------------------------------------
! compute the deformation gradient of individual grains due to relaxations
F = 0.0_pREAL
2020-09-23 05:03:19 +05:30
do iGrain = 1,product(prm%N_constituents)
iGrain3 = grain1to3(iGrain,prm%N_constituents)
2019-06-15 21:57:38 +05:30
do iFace = 1,6
intFace = getInterface(iFace,iGrain3) ! identifying 6 interfaces of each grain
2021-04-06 15:08:44 +05:30
aVect = relaxationVector(intFace,ho,en) ! get the relaxation vectors for each interface from global relaxation vector array
nVect = interfaceNormal(intFace,ho,en)
2019-06-15 21:57:38 +05:30
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
end do
2019-06-15 21:57:38 +05:30
F(1:3,1:3,iGrain) = F(1:3,1:3,iGrain) + avgF ! resulting relaxed deformation gradient
end do
2019-06-15 21:57:38 +05:30
end associate
end subroutine RGC_partitionDeformation
!--------------------------------------------------------------------------------------------------
!> @brief update the internal state of the homogenization scheme and tell whether "done" and
! "happy" with result
!--------------------------------------------------------------------------------------------------
module function RGC_updateState(P,F,avgF,dt,dPdF,ce) result(doneAndHappy)
2020-12-28 14:25:54 +05:30
logical, dimension(2) :: doneAndHappy
real(pREAL), dimension(:,:,:), intent(in) :: &
2020-12-28 14:25:54 +05:30
P,& !< partitioned stresses
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
2020-12-28 14:25:54 +05:30
integer, intent(in) :: &
2021-02-22 20:47:32 +05:30
ce !< cell
2018-11-03 21:20:43 +05:30
2019-06-15 21:57:38 +05:30
integer, dimension(4) :: intFaceN,intFaceP,faceID
integer, dimension(3) :: nGDim,iGr3N,iGr3P
2021-04-06 15:08:44 +05:30
integer :: ho,iNum,i,j,nIntFaceTot,iGrN,iGrP,iMun,iFace,k,l,ipert,nGrain, en
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
real(pREAL) :: residMax,stresMax
2019-06-15 21:57:38 +05:30
logical :: error
real(pREAL), dimension(:,:), allocatable :: tract,jmatrix,jnverse,smatrix,pmatrix,rmatrix
real(pREAL), dimension(:), allocatable :: resid,relax,p_relax,p_resid,drelax
zeroTimeStep: if (dEq0(dt)) then
2020-12-28 14:25:54 +05:30
doneAndHappy = .true. ! pretend everything is fine and return
return
end if zeroTimeStep
2023-01-23 13:01:59 +05:30
ho = material_ID_homogenization(ce)
en = material_entry_homogenization(ce)
associate(stt => state(ho), st0 => state0(ho), dst => dependentState(ho), prm => param(ho))
2019-01-13 03:37:35 +05:30
!--------------------------------------------------------------------------------------------------
! get the dimension of the cluster (grains and interfaces)
2020-09-23 05:03:19 +05:30
nGDim = prm%N_constituents
2019-06-15 21:57:38 +05:30
nGrain = product(nGDim)
nIntFaceTot = (nGDim(1)-1)*nGDim(2)*nGDim(3) &
+ nGDim(1)*(nGDim(2)-1)*nGDim(3) &
+ nGDim(1)*nGDim(2)*(nGDim(3)-1)
!--------------------------------------------------------------------------------------------------
! 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)
2021-04-06 15:08:44 +05:30
relax = stt%relaxationVector(:,en)
drelax = stt%relaxationVector(:,en) - st0%relaxationVector(:,en)
!--------------------------------------------------------------------------------------------------
! computing interface mismatch and stress penalty tensor for all interfaces of all grains
2021-04-06 15:08:44 +05:30
call stressPenalty(R,NN,avgF,F,ho,en)
!--------------------------------------------------------------------------------------------------
! calculating volume discrepancy and stress penalty related to overall volume discrepancy
2021-04-06 15:08:44 +05:30
call volumePenalty(D,dst%volumeDiscrepancy(en),avgF,F,nGrain)
!------------------------------------------------------------------------------------------------
! computing the residual stress from the balance of traction at all (interior) interfaces
2019-06-15 21:57:38 +05:30
do iNum = 1,nIntFaceTot
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)
2019-06-15 21:57:38 +05:30
iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate system (3-dimensional index)
iGrN = grain3to1(iGr3N,param(ho)%N_constituents) ! translate the local grain ID into global coordinate system (1-dimensional index)
2019-06-15 21:57:38 +05:30
intFaceN = getInterface(2*faceID(1),iGr3N)
2021-04-06 15:08:44 +05:30
normN = interfaceNormal(intFaceN,ho,en)
!--------------------------------------------------------------------------------------------------
! identify the right/up/front grain (+|P)
2019-06-15 21:57:38 +05:30
iGr3P = iGr3N
iGr3P(faceID(1)) = iGr3N(faceID(1))+1 ! identifying the grain ID in local coordinate system (3-dimensional index)
iGrP = grain3to1(iGr3P,param(ho)%N_constituents) ! translate the local grain ID into global coordinate system (1-dimensional index)
2019-06-15 21:57:38 +05:30
intFaceP = getInterface(2*faceID(1)-1,iGr3P)
2021-04-06 15:08:44 +05:30
normP = interfaceNormal(intFaceP,ho,en)
!--------------------------------------------------------------------------------------------------
! compute the residual of traction at the interface (in local system, 4-dimensional index)
2019-06-15 21:57:38 +05:30
do i = 1,3
tract(iNum,i) = sign(num%viscModus*(abs(drelax(i+3*(iNum-1)))/(num%refRelaxRate*dt))**num%viscPower, &
2019-06-15 21:57:38 +05:30
drelax(i+3*(iNum-1))) ! contribution from the relaxation viscosity
do j = 1,3
tract(iNum,i) = tract(iNum,i) + (P(i,j,iGrP) + R(i,j,iGrP) + D(i,j,iGrP))*normP(j) & ! contribution from material stress P, mismatch penalty R, and volume penalty D projected into the interface
+ (P(i,j,iGrN) + R(i,j,iGrN) + D(i,j,iGrN))*normN(j)
resid(i+3*(iNum-1)) = tract(iNum,i) ! translate the local residual into global 1-dimensional residual array
end do
end do
end do
!--------------------------------------------------------------------------------------------------
! convergence check for stress residual
2019-06-15 21:57:38 +05:30
stresMax = maxval(abs(P)) ! get the maximum of first Piola-Kirchhoff (material) stress
residMax = maxval(abs(tract)) ! get the maximum of the residual
2020-12-28 14:25:54 +05:30
doneAndHappy = .false.
!--------------------------------------------------------------------------------------------------
! If convergence reached => done and happy
if (residMax < num%rtol*stresMax .or. residMax < num%atol) then
2020-12-28 14:25:54 +05:30
doneAndHappy = .true.
dst%mismatch(1:3,en) = sum(NN,2)/real(nGrain,pREAL)
dst%relaxationRate_avg(en) = sum(abs(drelax))/dt/real(3*nIntFaceTot,pREAL)
2021-04-06 15:08:44 +05:30
dst%relaxationRate_max(en) = maxval(abs(drelax))/dt
2019-06-15 21:57:38 +05:30
return
!--------------------------------------------------------------------------------------------------
! if residual blows-up => done but unhappy
elseif (residMax > num%relMax*stresMax .or. residMax > num%absMax) then ! try to restart when residual blows up exceeding maximum bound
2020-12-28 14:25:54 +05:30
doneAndHappy = [.true.,.false.] ! with direct cut-back
2019-01-13 03:37:35 +05:30
return
end if
!---------------------------------------------------------------------------------------------------
! construct the global Jacobian matrix for updating the global relaxation vector array when
! convergence is not yet reached ...
!--------------------------------------------------------------------------------------------------
! ... of the constitutive stress tangent, assembled from dPdF or material constitutive model "smatrix"
allocate(smatrix(3*nIntFaceTot,3*nIntFaceTot), source=0.0_pREAL)
2019-06-15 21:57:38 +05:30
do iNum = 1,nIntFaceTot
faceID = interface1to4(iNum,param(ho)%N_constituents) ! assembling of local dPdF into global Jacobian matrix
!--------------------------------------------------------------------------------------------------
! identify the left/bottom/back grain (-|N)
2019-06-15 21:57:38 +05:30
iGr3N = faceID(2:4) ! identifying the grain ID in local coordinate sytem
iGrN = grain3to1(iGr3N,param(ho)%N_constituents) ! translate into global grain ID
2019-06-15 21:57:38 +05:30
intFaceN = getInterface(2*faceID(1),iGr3N) ! identifying the connecting interface in local coordinate system
2021-04-06 15:08:44 +05:30
normN = interfaceNormal(intFaceN,ho,en)
2019-06-15 21:57:38 +05:30
do iFace = 1,6
intFaceN = getInterface(iFace,iGr3N) ! identifying all interfaces that influence relaxation of the above interface
2021-04-06 15:08:44 +05:30
mornN = interfaceNormal(intFaceN,ho,en)
iMun = interface4to1(intFaceN,param(ho)%N_constituents) ! translate the interfaces ID into local 4-dimensional index
2019-06-15 21:57:38 +05:30
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) &
+ dPdF(i,k,j,l,iGrN)*normN(k)*mornN(l)
2021-11-17 13:41:30 +05:30
end do;end do;end do;end do
! projecting the material tangent dPdF into the interface
! to obtain the Jacobian matrix contribution of dPdF
end if
end do
!--------------------------------------------------------------------------------------------------
! identify the right/up/front grain (+|P)
2019-06-15 21:57:38 +05:30
iGr3P = iGr3N
iGr3P(faceID(1)) = iGr3N(faceID(1))+1 ! identifying the grain ID in local coordinate sytem
iGrP = grain3to1(iGr3P,param(ho)%N_constituents) ! translate into global grain ID
2019-06-15 21:57:38 +05:30
intFaceP = getInterface(2*faceID(1)-1,iGr3P) ! identifying the connecting interface in local coordinate system
2021-04-06 15:08:44 +05:30
normP = interfaceNormal(intFaceP,ho,en)
2019-06-15 21:57:38 +05:30
do iFace = 1,6
intFaceP = getInterface(iFace,iGr3P) ! identifying all interfaces that influence relaxation of the above interface
2021-04-06 15:08:44 +05:30
mornP = interfaceNormal(intFaceP,ho,en)
iMun = interface4to1(intFaceP,param(ho)%N_constituents) ! translate the interfaces ID into local 4-dimensional index
2019-06-15 21:57:38 +05:30
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) &
+ dPdF(i,k,j,l,iGrP)*normP(k)*mornP(l)
2021-11-17 13:41:30 +05:30
end do;end do;end do;end do
end if
end do
end do
!--------------------------------------------------------------------------------------------------
! ... of the stress penalty tangent (mismatch penalty and volume penalty, computed using numerical
! perturbation method) "pmatrix"
allocate(pmatrix(3*nIntFaceTot,3*nIntFaceTot), source=0.0_pREAL)
allocate(p_relax(3*nIntFaceTot), source=0.0_pREAL)
allocate(p_resid(3*nIntFaceTot), source=0.0_pREAL)
2019-06-15 21:57:38 +05:30
do ipert = 1,3*nIntFaceTot
p_relax = relax
p_relax(ipert) = relax(ipert) + num%pPert ! perturb the relaxation vector
2021-04-06 15:08:44 +05:30
stt%relaxationVector(:,en) = p_relax
call grainDeformation(pF,avgF,ho,en) ! rain deformation from perturbed state
call stressPenalty(pR,DevNull, avgF,pF,ho,en) ! stress penalty due to interface mismatch from perturbed state
2021-02-26 02:12:40 +05:30
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
2019-06-15 21:57:38 +05:30
do iNum = 1,nIntFaceTot
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)
2019-06-15 21:57:38 +05:30
iGr3N = faceID(2:4) ! identify the grain ID in local coordinate system (3-dimensional index)
iGrN = grain3to1(iGr3N,param(ho)%N_constituents) ! translate the local grain ID into global coordinate system (1-dimensional index)
2019-06-15 21:57:38 +05:30
intFaceN = getInterface(2*faceID(1),iGr3N) ! identify the interface ID of the grain
2021-04-06 15:08:44 +05:30
normN = interfaceNormal(intFaceN,ho,en)
!--------------------------------------------------------------------------------------------------
! identify the right/up/front grain (+|P)
2019-06-15 21:57:38 +05:30
iGr3P = iGr3N
iGr3P(faceID(1)) = iGr3N(faceID(1))+1 ! identify the grain ID in local coordinate system (3-dimensional index)
iGrP = grain3to1(iGr3P,param(ho)%N_constituents) ! translate the local grain ID into global coordinate system (1-dimensional index)
2019-06-15 21:57:38 +05:30
intFaceP = getInterface(2*faceID(1)-1,iGr3P) ! identify the interface ID of the grain
2021-04-06 15:08:44 +05:30
normP = interfaceNormal(intFaceP,ho,en)
!--------------------------------------------------------------------------------------------------
! compute the residual stress (contribution of mismatch and volume penalties) from perturbed state
! at all interfaces
2019-06-15 21:57:38 +05:30
do i = 1,3; do j = 1,3
p_resid(i+3*(iNum-1)) = p_resid(i+3*(iNum-1)) + (pR(i,j,iGrP) - R(i,j,iGrP))*normP(j) &
+ (pR(i,j,iGrN) - R(i,j,iGrN))*normN(j) &
+ (pD(i,j,iGrP) - D(i,j,iGrP))*normP(j) &
+ (pD(i,j,iGrN) - D(i,j,iGrN))*normN(j)
end do; end do
end do
pmatrix(:,ipert) = p_resid/num%pPert
end do
!--------------------------------------------------------------------------------------------------
! ... of the numerical viscosity traction "rmatrix"
allocate(rmatrix(3*nIntFaceTot,3*nIntFaceTot),source=0.0_pREAL)
2019-06-15 21:57:38 +05:30
do i=1,3*nIntFaceTot
rmatrix(i,i) = num%viscModus*num%viscPower/(num%refRelaxRate*dt)* & ! tangent due to numerical viscosity traction appears
(abs(drelax(i))/(num%refRelaxRate*dt))**(num%viscPower - 1.0_pREAL) ! only in the main diagonal term
end do
!--------------------------------------------------------------------------------------------------
! The overall Jacobian matrix summarizing contributions of smatrix, pmatrix, rmatrix
2019-06-15 21:57:38 +05:30
allocate(jmatrix(3*nIntFaceTot,3*nIntFaceTot)); jmatrix = smatrix + pmatrix + rmatrix
2019-01-13 03:37:35 +05:30
!--------------------------------------------------------------------------------------------------
! computing the update of the state variable (relaxation vectors) using the Jacobian matrix
allocate(jnverse(3*nIntFaceTot,3*nIntFaceTot),source=0.0_pREAL)
2019-09-21 06:50:33 +05:30
call math_invert(jnverse,error,jmatrix)
!--------------------------------------------------------------------------------------------------
! calculate the state update (global relaxation vectors) for the next Newton-Raphson iteration
drelax = 0.0_pREAL
2019-06-15 21:57:38 +05:30
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
end do; end do
2021-04-06 15:08:44 +05:30
stt%relaxationVector(:,en) = 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
2020-12-28 14:25:54 +05:30
doneAndHappy = [.true.,.false.]
2019-06-15 21:57:38 +05:30
!$OMP CRITICAL (write2out)
2021-02-26 02:12:40 +05:30
print'(a,i3,a,i3,a)',' RGC_updateState: enforces cutback'
2020-09-18 02:27:56 +05:30
print'(a,e15.8)',' due to large relaxation change = ',maxval(abs(drelax))
2020-09-22 16:39:12 +05:30
flush(IO_STDOUT)
2019-06-15 21:57:38 +05:30
!$OMP END CRITICAL (write2out)
end if
2019-06-15 21:57:38 +05:30
end associate
2018-11-04 01:41:43 +05:30
2019-06-15 21:57:38 +05:30
contains
!------------------------------------------------------------------------------------------------
!> @brief calculate stress-like penalty due to deformation mismatch
!------------------------------------------------------------------------------------------------
2021-04-06 15:08:44 +05:30
subroutine stressPenalty(rPen,nMis,avgF,fDef,ho,en)
2019-05-15 02:42:32 +05:30
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
2021-04-06 15:08:44 +05:30
integer, intent(in) :: ho, en
2019-06-15 21:57:38 +05:30
integer, dimension (4) :: intFace
integer, dimension (3) :: iGrain3,iGNghb3,nGDim
real(pREAL), dimension (3,3) :: gDef,nDef
real(pREAL), dimension (3) :: nVect,surfCorr
2019-06-15 21:57:38 +05:30
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
2018-11-04 03:53:52 +05:30
nGDim = param(ho)%N_constituents
rPen = 0.0_pREAL
nMis = 0.0_pREAL
2019-06-15 21:57:38 +05:30
!----------------------------------------------------------------------------------------------
! get the correction factor the modulus of penalty stress representing the evolution of area of
2019-06-15 21:57:38 +05:30
! the interfaces due to deformations
2018-11-04 03:43:20 +05:30
2021-04-06 15:08:44 +05:30
surfCorr = surfaceCorrection(avgF,ho,en)
2018-11-04 03:53:52 +05:30
2021-02-26 02:12:40 +05:30
associate(prm => param(ho))
2019-06-15 21:57:38 +05:30
!-----------------------------------------------------------------------------------------------
! computing the mismatch and penalty stress tensor of all grains
2020-09-23 05:03:19 +05:30
grainLoop: do iGrain = 1,product(prm%N_constituents)
2021-02-22 20:47:32 +05:30
muGrain = equivalentMu(iGrain,ce)
2020-12-28 14:57:52 +05:30
iGrain3 = grain1to3(iGrain,prm%N_constituents) ! get the grain ID in local 3-dimensional index (x,y,z)-position
2019-06-15 21:57:38 +05:30
interfaceLoop: do iFace = 1,6
intFace = getInterface(iFace,iGrain3) ! get the 4-dimensional index of the interface in local numbering system of the grain
2021-04-06 15:08:44 +05:30
nVect = interfaceNormal(intFace,ho,en)
2019-06-15 21:57:38 +05:30
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))
2019-06-15 21:57:38 +05:30
where(iGNghb3 < 1) iGNghb3 = nGDim
where(iGNghb3 >nGDim) iGNghb3 = 1
2020-09-23 05:03:19 +05:30
iGNghb = grain3to1(iGNghb3,prm%N_constituents) ! get the ID of the neighboring grain
2021-02-22 20:47:32 +05:30
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
2019-06-15 21:57:38 +05:30
!-------------------------------------------------------------------------------------------
! compute the mismatch tensor of all interfaces
nDefNorm = 0.0_pREAL
nDef = 0.0_pREAL
2019-06-15 21:57:38 +05:30
do i = 1,3; do j = 1,3
do k = 1,3; do l = 1,3
nDef(i,j) = nDef(i,j) - nVect(k)*gDef(i,l)*math_LeviCivita(j,k,l) ! compute the interface mismatch tensor from the jump of deformation gradient
end do; end do
2021-11-26 01:22:22 +05:30
nDefNorm = nDefNorm + nDef(i,j)**2 ! compute the norm of the mismatch tensor
end do; end do
2019-06-15 21:57:38 +05:30
nDefNorm = max(nDefToler,sqrt(nDefNorm)) ! approximation to zero mismatch if mismatch is zero (singularity)
nMis(abs(intFace(1)),iGrain) = nMis(abs(intFace(1)),iGrain) + nDefNorm ! total amount of mismatch experienced by the grain (at all six interfaces)
2019-01-13 03:37:35 +05:30
2019-06-15 21:57:38 +05:30
!-------------------------------------------------------------------------------------------
! compute the stress penalty of all interfaces
do i = 1,3; do j = 1,3; do k = 1,3; do l = 1,3
rPen(i,j,iGrain) = rPen(i,j,iGrain) + 0.5_pREAL*(muGrain*b + muGNghb*b)*prm%xi_alpha &
2020-09-23 05:03:19 +05:30
*surfCorr(abs(intFace(1)))/prm%D_alpha(abs(intFace(1))) &
*cosh(prm%c_alpha*nDefNorm) &
*0.5_pREAL*nVect(l)*nDef(i,k)/nDefNorm*math_LeviCivita(k,l,j) &
*tanh(nDefNorm/num%xSmoo)
2022-06-09 02:36:01 +05:30
end do; end do;end do; end do
end do interfaceLoop
end do grainLoop
2019-06-15 21:57:38 +05:30
end associate
2019-06-15 21:57:38 +05:30
end subroutine stressPenalty
2019-06-15 21:57:38 +05:30
!------------------------------------------------------------------------------------------------
!> @brief calculate stress-like penalty due to volume discrepancy
2019-06-15 21:57:38 +05:30
!------------------------------------------------------------------------------------------------
2021-02-26 02:12:40 +05:30
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
real(pREAL), dimension (:,:,:), intent(in) :: fDef ! deformation gradients
real(pREAL), dimension (3,3), intent(in) :: fAvg ! overall deformation gradient
2019-06-15 21:57:38 +05:30
integer, intent(in) :: &
2021-02-26 02:12:40 +05:30
Ngrain
real(pREAL), dimension(size(vPen,3)) :: gVol
2019-06-15 21:57:38 +05:30
integer :: i
2019-06-15 21:57:38 +05:30
!----------------------------------------------------------------------------------------------
! compute the volumes of grains and of cluster
vDiscrep = math_det33(fAvg) ! compute the volume of the cluster
do i = 1,nGrain
gVol(i) = math_det33(fDef(1:3,1:3,i)) ! compute the volume of individual grains
vDiscrep = vDiscrep - gVol(i)/real(nGrain,pREAL) ! calculate the difference/dicrepancy between
2019-01-13 03:37:35 +05:30
! the volume of the cluster and the the total volume of grains
end do
2019-06-15 21:57:38 +05:30
!----------------------------------------------------------------------------------------------
! calculate the stress and penalty due to volume discrepancy
vPen = 0.0_pREAL
2019-06-15 21:57:38 +05:30
do i = 1,nGrain
vPen(:,:,i) = -real(nGrain,pREAL)**(-1)*num%volDiscrMod*num%volDiscrPow/num%maxVolDiscr &
* sign((abs(vDiscrep)/num%maxVolDiscr)**(num%volDiscrPow - 1.0_pREAL),vDiscrep) &
2022-06-27 14:07:41 +05:30
* gVol(i)*transpose(math_inv33(fDef(:,:,i)))
end do
2018-11-04 02:06:49 +05:30
2019-06-15 21:57:38 +05:30
end subroutine volumePenalty
2018-11-04 02:06:49 +05:30
2019-06-15 21:57:38 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief compute the correction factor accouted for surface evolution (area change) due to
2019-06-15 21:57:38 +05:30
! deformation
!--------------------------------------------------------------------------------------------------
2021-04-06 15:08:44 +05:30
function surfaceCorrection(avgF,ho,en)
real(pREAL), dimension(3) :: surfaceCorrection
2019-06-15 21:57:38 +05:30
real(pREAL), dimension(3,3), intent(in) :: avgF !< average F
2019-06-15 21:57:38 +05:30
integer, intent(in) :: &
2021-02-26 02:12:40 +05:30
ho, &
2021-04-06 15:08:44 +05:30
en
real(pREAL), dimension(3,3) :: invC
real(pREAL), dimension(3) :: nVect
real(pREAL) :: detF
2019-06-15 21:57:38 +05:30
integer :: i,j,iBase
logical :: error
2019-09-21 06:58:46 +05:30
call math_invert33(invC,detF,error,matmul(transpose(avgF),avgF))
surfaceCorrection = 0.0_pREAL
2019-06-15 21:57:38 +05:30
do iBase = 1,3
2021-04-06 15:08:44 +05:30
nVect = interfaceNormal([iBase,1,1,1],ho,en)
2019-06-15 21:57:38 +05:30
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
end do; end do
2019-06-15 21:57:38 +05:30
surfaceCorrection(iBase) = sqrt(surfaceCorrection(iBase))*detF ! get the surface correction factor (area contraction/enlargement)
end do
2019-06-15 21:57:38 +05:30
end function surfaceCorrection
2018-11-04 02:06:49 +05:30
2020-12-28 15:33:29 +05:30
!-------------------------------------------------------------------------------------------------
2019-06-15 21:57:38 +05:30
!> @brief compute the equivalent shear and bulk moduli from the elasticity tensor
2020-12-28 15:33:29 +05:30
!-------------------------------------------------------------------------------------------------
real(pREAL) function equivalentMu(co,ce)
2019-06-15 21:57:38 +05:30
integer, intent(in) :: &
2021-11-19 02:29:09 +05:30
co,&
2021-02-26 02:12:40 +05:30
ce
real(pREAL), dimension(6,6) :: C
2023-01-23 13:01:59 +05:30
C = phase_homogenizedC66(material_ID_phase(co,ce),material_entry_phase(co,ce)) ! damage not included!
2023-07-15 23:58:57 +05:30
equivalentMu = crystal_isotropic_mu(C,'isostrain')
2020-12-28 15:33:29 +05:30
end function equivalentMu
2020-12-28 15:33:29 +05:30
!-------------------------------------------------------------------------------------------------
!> @brief calculating the grain deformation gradient (the same with
2019-06-15 21:57:38 +05:30
! homogenization_RGC_partitionDeformation, but used only for perturbation scheme)
2020-12-28 15:33:29 +05:30
!-------------------------------------------------------------------------------------------------
2021-04-06 15:08:44 +05:30
subroutine grainDeformation(F, avgF, ho, en)
real(pREAL), dimension(:,:,:), intent(out) :: F !< partitioned F per grain
real(pREAL), dimension(:,:), intent(in) :: avgF !< averaged F
integer, intent(in) :: &
2021-02-26 02:12:40 +05:30
ho, &
2021-04-06 15:08:44 +05:30
en
real(pREAL), dimension(3) :: aVect,nVect
2019-06-15 21:57:38 +05:30
integer, dimension(4) :: intFace
integer, dimension(3) :: iGrain3
integer :: iGrain,iFace,i,j
2020-12-28 15:33:29 +05:30
!-----------------------------------------------------------------------------------------------
2019-06-15 21:57:38 +05:30
! compute the deformation gradient of individual grains due to relaxations
2021-02-26 02:12:40 +05:30
associate (prm => param(ho))
F = 0.0_pREAL
2020-09-23 05:03:19 +05:30
do iGrain = 1,product(prm%N_constituents)
iGrain3 = grain1to3(iGrain,prm%N_constituents)
2019-06-15 21:57:38 +05:30
do iFace = 1,6
intFace = getInterface(iFace,iGrain3)
2021-04-06 15:08:44 +05:30
aVect = relaxationVector(intFace,ho,en)
nVect = interfaceNormal(intFace,ho,en)
2019-06-15 21:57:38 +05:30
forall (i=1:3,j=1:3) &
F(i,j,iGrain) = F(i,j,iGrain) + aVect(i)*nVect(j) ! effective relaxations
end do
2019-06-15 21:57:38 +05:30
F(1:3,1:3,iGrain) = F(1:3,1:3,iGrain) + avgF ! relaxed deformation gradient
end do
2019-06-15 21:57:38 +05:30
end associate
2019-06-15 21:57:38 +05:30
end subroutine grainDeformation
end function RGC_updateState
2019-04-30 22:15:16 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief writes results to HDF5 output file
!--------------------------------------------------------------------------------------------------
2023-01-19 22:07:45 +05:30
module subroutine RGC_result(ho,group)
2019-04-30 22:15:16 +05:30
integer, intent(in) :: ho
character(len=*), intent(in) :: group
2019-04-30 22:15:16 +05:30
integer :: o
associate(stt => state(ho), dst => dependentState(ho), prm => param(ho))
2023-01-19 22:07:45 +05:30
outputsLoop: do o = 1,size(prm%output)
select case(trim(prm%output(o)))
case('M')
call result_writeDataset(dst%mismatch,group,trim(prm%output(o)), &
'average mismatch tensor','1')
case('Delta_V')
call result_writeDataset(dst%volumeDiscrepancy,group,trim(prm%output(o)), &
'volume discrepancy','m³')
case('max_dot_a')
call result_writeDataset(dst%relaxationrate_max,group,trim(prm%output(o)), &
'maximum relaxation rate','m/s')
case('avg_dot_a')
call result_writeDataset(dst%relaxationrate_avg,group,trim(prm%output(o)), &
'average relaxation rate','m/s')
end select
end do outputsLoop
2019-04-30 22:15:16 +05:30
end associate
2023-01-19 22:07:45 +05:30
end subroutine RGC_result
2019-04-30 22:15:16 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief collect relaxation vectors of an interface
!--------------------------------------------------------------------------------------------------
2021-04-06 15:08:44 +05:30
pure function relaxationVector(intFace,ho,en)
real(pREAL), dimension (3) :: relaxationVector
2019-04-06 00:15:56 +05:30
2021-04-06 15:08:44 +05:30
integer, intent(in) :: ho,en
2019-06-15 21:57:38 +05:30
integer, dimension(4), intent(in) :: intFace !< set of interface ID in 4D array (normal and position)
2019-06-15 21:57:38 +05:30
integer :: iNum
!--------------------------------------------------------------------------------------------------
! collect the interface relaxation vector from the global state array
2019-01-13 03:37:35 +05:30
2021-02-26 02:12:40 +05:30
associate (prm => param(ho), &
stt => state(ho))
2021-02-15 23:13:51 +05:30
iNum = interface4to1(intFace,prm%N_constituents) ! identify the position of the interface in global state array
2019-06-15 21:57:38 +05:30
if (iNum > 0) then
2021-04-06 15:08:44 +05:30
relaxationVector = stt%relaxationVector((3*iNum-2):(3*iNum),en)
2019-06-15 21:57:38 +05:30
else
relaxationVector = 0.0_pREAL
end if
2021-02-15 23:13:51 +05:30
end associate
end function relaxationVector
!--------------------------------------------------------------------------------------------------
!> @brief identify the normal of an interface
!--------------------------------------------------------------------------------------------------
pure function interfaceNormal(intFace,ho,en) result(n)
2019-04-06 00:15:56 +05:30
real(pREAL), dimension(3) :: n
2019-06-15 21:57:38 +05:30
integer, dimension(4), intent(in) :: intFace !< interface ID in 4D array (normal and position)
integer, intent(in) :: &
2021-02-26 02:12:40 +05:30
ho, &
2021-04-06 15:08:44 +05:30
en
2019-04-06 00:15:56 +05:30
2021-02-26 02:12:40 +05:30
associate (dst => dependentState(ho))
n = 0.0_pREAL
n(abs(intFace(1))) = real(intFace(1)/abs(intFace(1)),pREAL) ! get the normal vector w.r.t. cluster axis
2021-08-11 12:15:24 +05:30
n = matmul(dst%orientation(1:3,1:3,en),n) ! map the normal vector into sample coordinate system (basis)
2021-04-11 15:48:26 +05:30
2021-02-15 23:13:51 +05:30
end associate
end function interfaceNormal
!--------------------------------------------------------------------------------------------------
!> @brief collect six faces of a grain in 4D (normal and position)
!--------------------------------------------------------------------------------------------------
pure function getInterface(iFace,iGrain3) result(i)
2019-04-06 00:15:56 +05:30
integer, dimension(4) :: i
2019-06-15 21:57:38 +05:30
integer, dimension(3), intent(in) :: iGrain3 !< grain ID in 3D array
integer, intent(in) :: iFace !< face index (1..6) mapped like (-e1,-e2,-e3,+e1,+e2,+e3) or iDir = (-1,-2,-3,1,2,3)
2019-04-06 00:15:56 +05:30
2019-06-15 21:57:38 +05:30
integer :: iDir !< direction of interface normal
iDir = (int(real(iFace-1,pREAL)/2.0_pREAL)+1)*(-1)**iFace
i = [iDir,iGrain3]
if (iDir < 0) i(1-iDir) = i(1-iDir)-1 ! to have a correlation with coordinate/position in real space
end function getInterface
2018-11-04 12:41:35 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief map grain ID from in 1D (global array) to in 3D (local position)
!--------------------------------------------------------------------------------------------------
2018-11-04 12:41:35 +05:30
pure function grain1to3(grain1,nGDim)
2019-06-15 21:57:38 +05:30
integer, dimension(3) :: grain1to3
2019-04-06 00:15:56 +05:30
2019-06-15 21:57:38 +05:30
integer, intent(in) :: grain1 !< grain ID in 1D array
integer, dimension(3), intent(in) :: nGDim
2019-06-15 21:57:38 +05:30
grain1to3 = 1 + [mod((grain1-1), nGDim(1)), &
mod((grain1-1)/ nGDim(1),nGDim(2)), &
2019-04-06 00:15:56 +05:30
(grain1-1)/(nGDim(1)*nGDim(2))]
end function grain1to3
!--------------------------------------------------------------------------------------------------
!> @brief map grain ID from in 3D (local position) to in 1D (global array)
!--------------------------------------------------------------------------------------------------
2019-04-06 00:15:56 +05:30
integer pure function grain3to1(grain3,nGDim)
2019-06-15 21:57:38 +05:30
integer, dimension(3), intent(in) :: grain3 !< grain ID in 3D array (pos.x,pos.y,pos.z)
integer, dimension(3), intent(in) :: nGDim
2019-06-15 21:57:38 +05:30
grain3to1 = grain3(1) &
+ nGDim(1)*(grain3(2)-1) &
+ nGDim(1)*nGDim(2)*(grain3(3)-1)
end function grain3to1
!--------------------------------------------------------------------------------------------------
!> @brief maps interface ID from 4D (normal and local position) into 1D (global array)
!--------------------------------------------------------------------------------------------------
2019-04-06 00:15:56 +05:30
integer pure function interface4to1(iFace4D, nGDim)
2019-06-15 21:57:38 +05:30
integer, dimension(4), intent(in) :: iFace4D !< interface ID in 4D array (n.dir,pos.x,pos.y,pos.z)
integer, dimension(3), intent(in) :: nGDim
2019-06-15 21:57:38 +05:30
select case(abs(iFace4D(1)))
case(1)
if ((iFace4D(2) == 0) .or. (iFace4D(2) == nGDim(1))) then
interface4to1 = 0
else
interface4to1 = iFace4D(3) + nGDim(2)*(iFace4D(4)-1) &
+ nGDim(2)*nGDim(3)*(iFace4D(2)-1)
end if
2018-11-04 13:49:24 +05:30
2019-06-15 21:57:38 +05:30
case(2)
if ((iFace4D(3) == 0) .or. (iFace4D(3) == nGDim(2))) then
interface4to1 = 0
else
interface4to1 = iFace4D(4) + nGDim(3)*(iFace4D(2)-1) &
+ nGDim(3)*nGDim(1)*(iFace4D(3)-1) &
+ (nGDim(1)-1)*nGDim(2)*nGDim(3) ! total # of interfaces normal || e1
end if
2018-11-04 13:49:24 +05:30
2019-06-15 21:57:38 +05:30
case(3)
if ((iFace4D(4) == 0) .or. (iFace4D(4) == nGDim(3))) then
interface4to1 = 0
else
interface4to1 = iFace4D(2) + nGDim(1)*(iFace4D(3)-1) &
+ nGDim(1)*nGDim(2)*(iFace4D(4)-1) &
+ (nGDim(1)-1)*nGDim(2)*nGDim(3) & ! total # of interfaces normal || e1
+ nGDim(1)*(nGDim(2)-1)*nGDim(3) ! total # of interfaces normal || e2
end if
2018-11-04 13:49:24 +05:30
2019-06-15 21:57:38 +05:30
case default
interface4to1 = -1
2019-06-15 21:57:38 +05:30
end select
end function interface4to1
!--------------------------------------------------------------------------------------------------
!> @brief maps interface ID from 1D (global array) into 4D (normal and local position)
!--------------------------------------------------------------------------------------------------
2018-11-04 12:41:35 +05:30
pure function interface1to4(iFace1D, nGDim)
2019-06-15 21:57:38 +05:30
integer, dimension(4) :: interface1to4
2019-04-06 00:15:56 +05:30
2019-06-15 21:57:38 +05:30
integer, intent(in) :: iFace1D !< interface ID in 1D array
integer, dimension(3), intent(in) :: nGDim
integer, dimension(3) :: nIntFace
!--------------------------------------------------------------------------------------------------
! compute the total number of interfaces, which ...
2019-06-15 21:57:38 +05:30
nIntFace = [(nGDim(1)-1)*nGDim(2)*nGDim(3), & ! ... normal || e1
nGDim(1)*(nGDim(2)-1)*nGDim(3), & ! ... normal || e2
nGDim(1)*nGDim(2)*(nGDim(3)-1)] ! ... normal || e3
!--------------------------------------------------------------------------------------------------
! get the corresponding interface ID in 4D (normal and local position)
2019-06-15 21:57:38 +05:30
if (iFace1D > 0 .and. iFace1D <= nIntFace(1)) then ! interface with normal || e1
interface1to4(1) = 1
interface1to4(3) = mod((iFace1D-1),nGDim(2))+1
interface1to4(4) = mod(int(real(iFace1D-1,pREAL)/real(nGDim(2),pREAL)),nGDim(3))+1
interface1to4(2) = int(real(iFace1D-1,pREAL)/real(nGDim(2),pREAL)/real(nGDim(3),pREAL))+1
2019-06-15 21:57:38 +05:30
elseif (iFace1D > nIntFace(1) .and. iFace1D <= (nIntFace(2) + nIntFace(1))) then ! interface with normal || e2
interface1to4(1) = 2
interface1to4(4) = mod((iFace1D-nIntFace(1)-1),nGDim(3))+1
interface1to4(2) = mod(int(real(iFace1D-nIntFace(1)-1,pREAL)/real(nGDim(3),pREAL)),nGDim(1))+1
interface1to4(3) = int(real(iFace1D-nIntFace(1)-1,pREAL)/real(nGDim(3),pREAL)/real(nGDim(1),pREAL))+1
2019-06-15 21:57:38 +05:30
elseif (iFace1D > nIntFace(2) + nIntFace(1) .and. iFace1D <= (nIntFace(3) + nIntFace(2) + nIntFace(1))) then ! interface with normal || e3
interface1to4(1) = 3
interface1to4(2) = mod((iFace1D-nIntFace(2)-nIntFace(1)-1),nGDim(1))+1
interface1to4(3) = mod(int(real(iFace1D-nIntFace(2)-nIntFace(1)-1,pREAL)/real(nGDim(1),pREAL)),nGDim(2))+1
interface1to4(4) = int(real(iFace1D-nIntFace(2)-nIntFace(1)-1,pREAL)/real(nGDim(1),pREAL)/real(nGDim(2),pREAL))+1
end if
end function interface1to4
2021-01-26 16:11:19 +05:30
end submodule RGC