2012-07-30 19:36:22 +05:30
!--------------------------------------------------------------------------------------------------
2012-08-03 14:55:48 +05:30
! $Id$
2012-07-30 19:36:22 +05:30
!--------------------------------------------------------------------------------------------------
!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH
!> @author Martin Diehl, Max-Planck-Institut für Eisenforschung GmbH
!> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH
!> @brief Basic scheme solver
2012-08-29 00:49:47 +05:30
!> @details this solver follows closely the original large strain formulation presented by
!> Suquet. The iterative procedure is solved using a fix-point iteration
2012-07-30 19:36:22 +05:30
!--------------------------------------------------------------------------------------------------
2012-07-24 22:37:10 +05:30
module DAMASK_spectral_SolverBasic
2012-08-03 14:55:48 +05:30
use prec , only : &
pInt , &
pReal
2012-07-30 19:36:22 +05:30
use math , only : &
2012-08-03 14:55:48 +05:30
math_I3
use DAMASK_spectral_Utilities , only : &
2012-10-02 20:56:56 +05:30
tSolutionState
2012-07-25 19:31:39 +05:30
2012-08-03 14:55:48 +05:30
implicit none
2012-07-25 19:31:39 +05:30
character ( len = * ) , parameter , public :: &
DAMASK_spectral_SolverBasic_label = 'basic'
!--------------------------------------------------------------------------------------------------
2012-11-12 19:44:39 +05:30
! pointwise global data
real ( pReal ) , private , dimension ( : , : , : , : , : ) , allocatable :: &
F , & !< deformation gradient field
F_lastInc , & !< deformation gradient field last increment
Fdot !< assumed rate for F n to F n+1
real ( pReal ) , private :: temperature !< not pointwise
2012-07-25 19:31:39 +05:30
!--------------------------------------------------------------------------------------------------
! stress, stiffness and compliance average etc.
2012-08-03 14:55:48 +05:30
real ( pReal ) , private , dimension ( 3 , 3 ) :: &
2012-11-12 19:44:39 +05:30
F_aim = math_I3 , & !< deformation gradient aim
F_aim_lastInc = math_I3 , & !< deformation gradient aim last increment
F_aimDot = 0.0_pReal !< assumed rate
2012-08-03 14:55:48 +05:30
real ( pReal ) , private , dimension ( 3 , 3 , 3 , 3 ) :: &
2012-11-12 19:44:39 +05:30
C = 0.0_pReal , & !< average stiffness
C_lastInc = 0.0_pReal !< average stiffness last increment
2012-07-25 19:31:39 +05:30
2012-08-29 00:49:47 +05:30
contains
2012-07-24 22:37:10 +05:30
2012-08-03 14:55:48 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief allocates all neccessary fields and fills them with data, potentially from restart info
!--------------------------------------------------------------------------------------------------
subroutine basic_init ( )
2012-08-27 13:34:47 +05:30
use , intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment)
2012-08-03 14:55:48 +05:30
use IO , only : &
IO_read_JobBinaryFile , &
2012-08-31 01:56:28 +05:30
IO_write_JobBinaryFile , &
IO_intOut
2012-08-03 14:55:48 +05:30
use FEsolving , only : &
restartInc
use DAMASK_interface , only : &
getSolverJobName
use DAMASK_spectral_Utilities , only : &
Utilities_init , &
Utilities_constitutiveResponse , &
Utilities_updateGamma , &
2012-10-02 20:56:56 +05:30
debugRestart
2012-08-03 14:55:48 +05:30
use mesh , only : &
res , &
2012-11-14 20:08:10 +05:30
geomdim , &
mesh_ipCoordinates , &
mesh_NcpElems , &
mesh_deformedCoordsFFT
2012-08-03 14:55:48 +05:30
implicit none
2012-11-12 19:44:39 +05:30
real ( pReal ) , dimension ( 3 , 3 , res ( 1 ) , res ( 2 ) , res ( 3 ) ) :: P
integer ( pInt ) :: &
i , j , k
real ( pReal ) , dimension ( 3 , 3 ) :: &
temp33_Real
real ( pReal ) , dimension ( 3 , 3 , 3 , 3 ) :: &
temp3333_Real
2012-07-30 19:36:22 +05:30
2012-10-24 17:01:40 +05:30
2012-08-03 14:55:48 +05:30
call Utilities_Init ( )
2012-10-02 20:56:56 +05:30
write ( 6 , '(/,a)' ) ' <<<+- DAMASK_spectral_solverBasic init -+>>>'
2012-08-03 14:55:48 +05:30
write ( 6 , '(a)' ) ' $Id$'
2012-07-30 19:36:22 +05:30
#include "compilation_info.f90"
2012-08-03 14:55:48 +05:30
write ( 6 , '(a)' ) ''
2012-11-12 19:44:39 +05:30
!--------------------------------------------------------------------------------------------------
! allocate global fields
2012-08-09 18:34:56 +05:30
allocate ( F ( 3 , 3 , res ( 1 ) , res ( 2 ) , res ( 3 ) ) , source = 0.0_pReal )
allocate ( F_lastInc ( 3 , 3 , res ( 1 ) , res ( 2 ) , res ( 3 ) ) , source = 0.0_pReal )
2012-10-02 20:56:56 +05:30
allocate ( Fdot ( 3 , 3 , res ( 1 ) , res ( 2 ) , res ( 3 ) ) , source = 0.0_pReal )
2012-07-25 19:31:39 +05:30
!--------------------------------------------------------------------------------------------------
2012-11-12 19:44:39 +05:30
! init fields and average quantities
2012-08-03 14:55:48 +05:30
if ( restartInc == 1_pInt ) then ! no deformation (no restart)
2012-08-09 18:34:56 +05:30
F = spread ( spread ( spread ( math_I3 , 3 , res ( 1 ) ) , 4 , res ( 2 ) ) , 5 , res ( 3 ) ) ! initialize to identity
F_lastInc = F
2012-08-03 14:55:48 +05:30
elseif ( restartInc > 1_pInt ) then ! using old values from file
2012-08-31 01:56:28 +05:30
if ( debugRestart ) write ( 6 , '(a,' / / IO_intOut ( restartInc - 1_pInt ) / / ',a)' ) &
'Reading values of increment' , restartInc - 1_pInt , 'from file'
2012-08-03 14:55:48 +05:30
call IO_read_jobBinaryFile ( 777 , 'convergedSpectralDefgrad' , &
2012-07-25 19:31:39 +05:30
trim ( getSolverJobName ( ) ) , size ( F ) )
2012-08-03 14:55:48 +05:30
read ( 777 , rec = 1 ) F
close ( 777 )
call IO_read_jobBinaryFile ( 777 , 'convergedSpectralDefgrad_lastInc' , &
2012-07-25 19:31:39 +05:30
trim ( getSolverJobName ( ) ) , size ( F_lastInc ) )
2012-08-03 14:55:48 +05:30
read ( 777 , rec = 1 ) F_lastInc
close ( 777 )
call IO_read_jobBinaryFile ( 777 , 'F_aim' , trim ( getSolverJobName ( ) ) , size ( F_aim ) )
read ( 777 , rec = 1 ) F_aim
close ( 777 )
call IO_read_jobBinaryFile ( 777 , 'F_aim_lastInc' , trim ( getSolverJobName ( ) ) , size ( F_aim_lastInc ) )
read ( 777 , rec = 1 ) F_aim_lastInc
close ( 777 )
2012-10-24 17:01:40 +05:30
call IO_read_jobBinaryFile ( 777 , 'C_lastInc' , trim ( getSolverJobName ( ) ) , size ( C_lastInc ) )
read ( 777 , rec = 1 ) C_lastInc
close ( 777 )
call IO_read_jobBinaryFile ( 777 , 'C' , trim ( getSolverJobName ( ) ) , size ( C ) )
read ( 777 , rec = 1 ) C
close ( 777 )
call IO_read_jobBinaryFile ( 777 , 'F_aimDot' , trim ( getSolverJobName ( ) ) , size ( f_aimDot ) )
read ( 777 , rec = 1 ) f_aimDot
close ( 777 )
call IO_read_jobBinaryFile ( 777 , 'C_ref' , trim ( getSolverJobName ( ) ) , size ( temp3333_Real ) )
read ( 777 , rec = 1 ) temp3333_Real
close ( 777 )
2012-08-03 14:55:48 +05:30
endif
2012-11-14 20:08:10 +05:30
mesh_ipCoordinates = 0.0_pReal !reshape(mesh_deformedCoordsFFT(geomdim,&
!reshape(F,[3,3,res(1),res(2),res(3)])),[3,1,mesh_NcpElems])
call Utilities_constitutiveResponse ( F , F , temperature , 0.0_pReal , P , C , temp33_Real , . false . , math_I3 ) ! constitutive response with no deformation in no time to get reference stiffness
2012-10-24 17:01:40 +05:30
if ( restartInc == 1_pInt ) then ! use initial stiffness as reference stiffness
temp3333_Real = C
endif
2012-07-25 19:31:39 +05:30
2012-10-24 17:01:40 +05:30
call Utilities_updateGamma ( temp3333_Real , . True . )
2012-07-24 22:37:10 +05:30
2012-08-03 14:55:48 +05:30
end subroutine basic_init
!--------------------------------------------------------------------------------------------------
!> @brief solution for the basic scheme with internal iterations
!--------------------------------------------------------------------------------------------------
2012-10-02 20:56:56 +05:30
type ( tSolutionState ) function &
2012-11-09 01:02:00 +05:30
basic_solution ( incInfo , guess , timeinc , timeinc_old , P_BC , F_BC , temperature_bc , rotation_BC )
2012-07-24 22:37:10 +05:30
use numerics , only : &
2012-07-26 19:28:47 +05:30
itmax , &
itmin , &
update_gamma
2012-08-03 14:55:48 +05:30
use math , only : &
math_mul33x33 , &
math_rotate_backward33 , &
math_transpose33 , &
2012-08-27 13:34:47 +05:30
math_mul3333xx33
2012-08-03 14:55:48 +05:30
use mesh , only : &
res , &
2012-08-27 13:34:47 +05:30
geomdim , &
2012-11-14 20:08:10 +05:30
wgt , &
mesh_ipCoordinates , &
mesh_NcpElems , &
mesh_deformedCoordsFFT
2012-07-24 22:37:10 +05:30
use IO , only : &
2012-08-31 01:56:28 +05:30
IO_write_JobBinaryFile , &
IO_intOut
2012-08-03 14:55:48 +05:30
use DAMASK_spectral_Utilities , only : &
2012-10-02 20:56:56 +05:30
tBoundaryCondition , &
2012-08-03 14:55:48 +05:30
field_real , &
Utilities_forwardField , &
Utilities_maskedCompliance , &
2012-10-02 20:56:56 +05:30
Utilities_FFTforward , &
2012-08-03 14:55:48 +05:30
Utilities_divergenceRMS , &
Utilities_fourierConvolution , &
2012-10-02 20:56:56 +05:30
Utilities_FFTbackward , &
2012-08-03 14:55:48 +05:30
Utilities_updateGamma , &
2012-10-02 20:56:56 +05:30
Utilities_constitutiveResponse , &
Utilities_calculateRate
2012-07-24 22:37:10 +05:30
use FEsolving , only : &
2012-08-29 11:20:42 +05:30
restartWrite , &
2012-10-24 17:01:40 +05:30
restartRead , &
2012-08-29 11:20:42 +05:30
terminallyIll
2012-10-24 17:01:40 +05:30
use DAMASK_spectral_Utilities , only : &
cutBack
2012-07-24 22:37:10 +05:30
implicit none
!--------------------------------------------------------------------------------------------------
! input data for solution
2012-11-12 19:44:39 +05:30
real ( pReal ) , intent ( in ) :: &
timeinc , & !< increment in time for current solution
timeinc_old , & !< increment in time of last increment
temperature_bc !< temperature (I wonder, why it is intent(in)
logical , intent ( in ) :: &
guess !< if .false., assume homogeneous addon
type ( tBoundaryCondition ) , intent ( in ) :: &
P_BC , & !< stress boundary conditions
F_BC !< deformation boundary conditions
character ( len = * ) , intent ( in ) :: &
incInfo !< string with information of current increment for output to screen
real ( pReal ) , dimension ( 3 , 3 ) , intent ( in ) :: &
rotation_BC !< rotation load to lab
2012-07-24 22:37:10 +05:30
2012-11-12 19:44:39 +05:30
real ( pReal ) , dimension ( 3 , 3 , 3 , 3 ) :: &
S !< current average compliance
real ( pReal ) , dimension ( 3 , 3 ) :: &
F_aim_lab , &
F_aim_lab_lastIter , & !< aim of last iteration
P_av
real ( pReal ) , dimension ( 3 , 3 , res ( 1 ) , res ( 2 ) , res ( 3 ) ) :: P
2012-08-03 14:55:48 +05:30
!--------------------------------------------------------------------------------------------------
! loop variables, convergence etc.
2012-07-25 19:31:39 +05:30
real ( pReal ) :: err_div , err_stress
2012-08-03 14:55:48 +05:30
integer ( pInt ) :: iter , row , column , i , j , k
2012-07-25 19:31:39 +05:30
logical :: ForwardData
2012-11-12 19:44:39 +05:30
real ( pReal ) :: &
defgradDet , &
defgradDetMax , &
defgradDetMin
2012-08-03 14:55:48 +05:30
real ( pReal ) , dimension ( 3 , 3 ) :: temp33_Real
2012-07-24 22:37:10 +05:30
2012-08-03 14:55:48 +05:30
!--------------------------------------------------------------------------------------------------
2012-11-12 19:44:39 +05:30
! write restart information for spectral solver
2012-07-24 22:37:10 +05:30
if ( restartWrite ) then
write ( 6 , '(a)' ) 'writing converged results for restart'
2012-10-24 17:01:40 +05:30
call IO_write_jobBinaryFile ( 777 , 'convergedSpectralDefgrad' , size ( F ) ) ! writing deformation gradient field to file
write ( 777 , rec = 1 ) F
close ( 777 )
call IO_write_jobBinaryFile ( 777 , 'convergedSpectralDefgrad_lastInc' , size ( F_lastInc ) ) ! writing F_lastInc field to file
write ( 777 , rec = 1 ) F_lastInc
2012-07-24 22:37:10 +05:30
close ( 777 )
2012-10-24 17:01:40 +05:30
call IO_write_jobBinaryFile ( 777 , 'F_aim' , size ( F_aim ) )
write ( 777 , rec = 1 ) F_aim
close ( 777 )
call IO_write_jobBinaryFile ( 777 , 'F_aim_lastInc' , size ( F_aim_lastInc ) )
write ( 777 , rec = 1 ) F_aim_lastInc
close ( 777 )
2012-07-24 22:37:10 +05:30
call IO_write_jobBinaryFile ( 777 , 'C' , size ( C ) )
write ( 777 , rec = 1 ) C
close ( 777 )
2012-10-24 17:01:40 +05:30
call IO_write_jobBinaryFile ( 777 , 'C_lastInc' , size ( C_lastInc ) )
write ( 777 , rec = 1 ) C_lastInc
close ( 777 )
call IO_write_jobBinaryFile ( 777 , 'F_aimDot' , size ( f_aimDot ) )
write ( 777 , rec = 1 ) f_aimDot
close ( 777 )
2012-07-24 22:37:10 +05:30
endif
2012-11-12 19:44:39 +05:30
!--------------------------------------------------------------------------------------------------
! forward data
if ( cutBack ) then
2012-10-24 17:01:40 +05:30
F_aim = F_aim_lastInc
F = F_lastInc
C = C_lastInc
else
2012-11-12 19:44:39 +05:30
C_lastInc = C
2012-11-14 20:08:10 +05:30
mesh_ipCoordinates = 0.0_pReal !reshape(mesh_deformedCoordsFFT(geomdim,&
!reshape(F,[3,3,res(1),res(2),res(3)])),[3,1,mesh_NcpElems])
2012-10-02 20:56:56 +05:30
if ( F_BC % myType == 'l' ) then ! calculate f_aimDot from given L and current F
f_aimDot = F_BC % maskFloat * math_mul33x33 ( F_BC % values , F_aim )
elseif ( F_BC % myType == 'fdot' ) then ! f_aimDot is prescribed
f_aimDot = F_BC % maskFloat * F_BC % values
endif
2012-11-09 01:02:00 +05:30
if ( guess ) f_aimDot = f_aimDot + P_BC % maskFloat * ( F_aim - F_aim_lastInc ) / timeinc_old
2012-10-02 20:56:56 +05:30
F_aim_lastInc = F_aim
Fdot = Utilities_calculateRate ( math_rotate_backward33 ( f_aimDot , rotation_BC ) , &
2012-11-09 01:02:00 +05:30
timeinc , timeinc_old , guess , F_lastInc , F )
2012-10-02 20:56:56 +05:30
F_lastInc = F
endif
F_aim = F_aim + f_aimDot * timeinc
2012-10-24 17:01:40 +05:30
F = Utilities_forwardField ( timeinc , F_aim , F_lastInc , Fdot ) !I think F aim should be rotated here
2012-10-19 14:14:21 +05:30
2012-08-03 14:55:48 +05:30
!--------------------------------------------------------------------------------------------------
! update stiffness (and gamma operator)
S = Utilities_maskedCompliance ( rotation_BC , P_BC % maskLogical , C )
2012-10-24 17:01:40 +05:30
if ( update_gamma ) call Utilities_updateGamma ( C , restartWrite )
2012-08-03 14:55:48 +05:30
2012-11-12 19:44:39 +05:30
!--------------------------------------------------------------------------------------------------
! iteration till converged
2012-10-24 17:01:40 +05:30
if ( . not . restartRead ) ForwardData = . True .
2012-08-03 14:55:48 +05:30
iter = 0_pInt
convergenceLoop : do while ( iter < itmax )
2012-07-24 22:37:10 +05:30
iter = iter + 1_pInt
!--------------------------------------------------------------------------------------------------
! report begin of new iteration
2012-10-02 20:56:56 +05:30
write ( 6 , '(/,a,3(a,' / / IO_intOut ( itmax ) / / '))' ) trim ( incInfo ) , &
2012-10-19 14:14:21 +05:30
' @ Iter. ' , itmin , '≤' , iter , '≤' , itmax
2012-08-03 14:55:48 +05:30
write ( 6 , '(a,/,3(3(f12.7,1x)/))' , advance = 'no' ) 'deformation gradient aim =' , &
math_transpose33 ( F_aim )
2012-07-24 22:37:10 +05:30
!--------------------------------------------------------------------------------------------------
! evaluate constitutive response
2012-11-12 19:44:39 +05:30
F_aim_lab_lastIter = math_rotate_backward33 ( F_aim , rotation_BC )
2012-10-02 20:56:56 +05:30
basic_solution % termIll = . false .
2012-11-14 20:08:10 +05:30
call Utilities_constitutiveResponse ( F_lastInc , F , temperature , timeinc , &
2012-08-03 14:55:48 +05:30
P , C , P_av , ForwardData , rotation_BC )
2012-08-29 11:20:42 +05:30
basic_solution % termIll = terminallyIll
2012-11-12 19:44:39 +05:30
terminallyIll = . false .
ForwardData = . false .
2012-07-25 19:31:39 +05:30
2012-07-24 22:37:10 +05:30
!--------------------------------------------------------------------------------------------------
! stress BC handling
2012-10-02 20:56:56 +05:30
F_aim = F_aim - math_mul3333xx33 ( S , ( ( P_av - P_BC % values ) ) ) ! S = 0.0 for no bc
err_stress = maxval ( abs ( P_BC % maskFloat * ( P_av - P_BC % values ) ) ) ! mask = 0.0 for no bc
F_aim_lab = math_rotate_backward33 ( F_aim , rotation_BC ) ! boundary conditions from load frame into lab (Fourier) frame
2012-07-24 22:37:10 +05:30
!--------------------------------------------------------------------------------------------------
2012-08-03 14:55:48 +05:30
! updated deformation gradient using fix point algorithm of basic scheme
field_real = 0.0_pReal
2012-08-09 18:34:56 +05:30
field_real ( 1 : res ( 1 ) , 1 : res ( 2 ) , 1 : res ( 3 ) , 1 : 3 , 1 : 3 ) = reshape ( P , [ res ( 1 ) , res ( 2 ) , res ( 3 ) , 3 , 3 ] , &
order = [ 4 , 5 , 1 , 2 , 3 ] ) ! field real has a different order
2012-10-02 20:56:56 +05:30
call Utilities_FFTforward ( )
2012-08-03 14:55:48 +05:30
err_div = Utilities_divergenceRMS ( )
call Utilities_fourierConvolution ( F_aim_lab_lastIter - F_aim_lab )
2012-10-02 20:56:56 +05:30
call Utilities_FFTbackward ( )
2012-08-09 18:34:56 +05:30
F = F - reshape ( field_real ( 1 : res ( 1 ) , 1 : res ( 2 ) , 1 : res ( 3 ) , 1 : 3 , 1 : 3 ) , shape ( F ) , order = [ 3 , 4 , 5 , 1 , 2 ] ) ! F(x)^(n+1) = F(x)^(n) + correction; *wgt: correcting for missing normalization
2012-08-06 14:23:12 +05:30
basic_solution % converged = basic_Converged ( err_div , P_av , err_stress , P_av )
2012-10-02 20:56:56 +05:30
write ( 6 , '(/,a)' ) '=========================================================================='
2012-10-19 14:14:21 +05:30
if ( ( basic_solution % converged . and . iter > = itmin ) . or . basic_solution % termIll ) then
basic_solution % iterationsNeeded = iter
exit
endif
2012-07-24 22:37:10 +05:30
enddo convergenceLoop
end function basic_solution
2012-08-03 14:55:48 +05:30
!--------------------------------------------------------------------------------------------------
!> @brief convergence check for basic scheme based on div of P and deviation from stress aim
!--------------------------------------------------------------------------------------------------
2012-08-06 14:23:12 +05:30
logical function basic_Converged ( err_div , pAvgDiv , err_stress , pAvgStress )
2012-07-30 19:36:22 +05:30
use numerics , only : &
2012-08-03 14:55:48 +05:30
itmin , &
err_div_tol , &
err_stress_tolrel , &
err_stress_tolabs
use math , only : &
math_mul33x33 , &
math_eigenvalues33 , &
math_transpose33
2012-07-26 19:28:47 +05:30
2012-07-30 19:36:22 +05:30
implicit none
2012-08-03 14:55:48 +05:30
real ( pReal ) , dimension ( 3 , 3 ) , intent ( in ) :: &
pAvgDiv , &
pAvgStress
real ( pReal ) , intent ( in ) :: &
err_div , &
err_stress
real ( pReal ) :: &
err_stress_tol , &
pAvgDivL2
2012-07-26 19:28:47 +05:30
2012-08-03 14:55:48 +05:30
pAvgDivL2 = sqrt ( maxval ( math_eigenvalues33 ( math_mul33x33 ( pAvgDiv , math_transpose33 ( pAvgDiv ) ) ) ) ) ! L_2 norm of average stress (http://mathworld.wolfram.com/SpectralNorm.html)
err_stress_tol = min ( maxval ( abs ( pAvgStress ) ) * err_stress_tolrel , err_stress_tolabs )
2012-08-06 14:23:12 +05:30
basic_Converged = all ( [ err_div / pAvgDivL2 / err_div_tol , &
2012-08-03 14:55:48 +05:30
err_stress / err_stress_tol ] < 1.0_pReal )
2012-07-26 19:28:47 +05:30
2012-08-03 14:55:48 +05:30
write ( 6 , '(a,f6.2,a,es11.4,a)' ) 'error divergence = ' , err_div / pAvgDivL2 / err_div_tol , &
' (' , err_div , ' N/m³)'
write ( 6 , '(a,f6.2,a,es11.4,a)' ) 'error stress = ' , err_stress / err_stress_tol , &
' (' , err_stress , ' Pa)'
2012-07-26 19:28:47 +05:30
2012-08-06 14:23:12 +05:30
end function basic_Converged
2012-07-25 19:31:39 +05:30
2012-10-02 20:56:56 +05:30
2012-08-03 14:55:48 +05:30
subroutine basic_destroy ( )
2012-11-12 19:44:39 +05:30
use DAMASK_spectral_Utilities , only : &
Utilities_destroy
2012-08-03 14:55:48 +05:30
implicit none
call Utilities_destroy ( )
2012-07-25 19:31:39 +05:30
end subroutine basic_destroy
2012-10-02 20:56:56 +05:30
2012-07-25 19:31:39 +05:30
end module DAMASK_spectral_SolverBasic