From c341ddd855efa839aba7dfcee0fb5bb99a470914 Mon Sep 17 00:00:00 2001 From: Pratheek Shanthraj Date: Thu, 26 Jul 2012 13:58:47 +0000 Subject: [PATCH] =?UTF-8?q?more=20modularization=E2=80=A6.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/DAMASK_spectral_SolverAL.f90 | 353 +++++++++++++++++-- code/DAMASK_spectral_SolverBasic.f90 | 98 ++++-- code/DAMASK_spectral_Utilities.f90 | 501 +++++++++++++-------------- 3 files changed, 643 insertions(+), 309 deletions(-) diff --git a/code/DAMASK_spectral_SolverAL.f90 b/code/DAMASK_spectral_SolverAL.f90 index 03923f7df..3f73ccc20 100644 --- a/code/DAMASK_spectral_SolverAL.f90 +++ b/code/DAMASK_spectral_SolverAL.f90 @@ -11,10 +11,28 @@ module DAMASK_spectral_SolverAL mesh_spectral_getDimension implicit none +#include +#include character (len=*), parameter, public :: & DAMASK_spectral_SolverAL_label = 'AL' +!-------------------------------------------------------------------------------------------------- +! PETSc data + SNES snes + KSP ksp + DM da + Vec x,r + PetscErrorCode ierr_psc + PetscMPIInt rank + PetscObject dummy + PetscInt xs,xm,gxs,gxm + PetscInt ys,ym,gys,gym + PetscInt zs,zm,gzs,gzm + character(len=1024) :: PetSc_options = '-snes_type ngmres -snes_ngmres_anderson -snes_monitor -snes_view' + + external FormFunctionLocal, SNESConverged_Interactive + !-------------------------------------------------------------------------------------------------- ! common pointwise data real(pReal), dimension(:,:,:,:,:), allocatable :: F, F_lastInc, F_lambda, F_lambda_lastInc, P @@ -27,12 +45,13 @@ module DAMASK_spectral_SolverAL F_aim = math_I3, & F_aim_lastInc = math_I3, & P_av + real(pReal), dimension(3,3,3,3) :: & C_ref = 0.0_pReal, & C = 0.0_pReal -!-------------------------------------------------------------------------------------------------- -! solution state + integer(pInt) :: iter + real(pReal) :: err_div, err_stress contains @@ -49,13 +68,14 @@ module DAMASK_spectral_SolverAL getSolverJobName implicit none + integer(pInt) :: i,j,k - integer(pInt) :: i, j, k - res = mesh_spectral_getResolution() - geomdim = mesh_spectral_getDimension() + call Utilities_init() allocate (F ( res(1), res(2),res(3),3,3), source = 0.0_pReal) allocate (F_lastInc ( res(1), res(2),res(3),3,3), source = 0.0_pReal) + allocate (F_lambda ( res(1), res(2),res(3),3,3), source = 0.0_pReal) + allocate (F_lambda_lastInc(res(1),res(2),res(3),3,3), source = 0.0_pReal) allocate (P ( res(1), res(2),res(3),3,3), source = 0.0_pReal) allocate (coordinates( res(1), res(2),res(3),3), source = 0.0_pReal) allocate (temperature( res(1), res(2),res(3)), source = 0.0_pReal) @@ -66,6 +86,8 @@ module DAMASK_spectral_SolverAL do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) F(i,j,k,1:3,1:3) = math_I3 F_lastInc(i,j,k,1:3,1:3) = math_I3 + F_lambda(i,j,k,1:3,1:3) = math_I3 + F_lambda_lastInc(i,j,k,1:3,1:3) = math_I3 coordinates(i,j,k,1:3) = geomdim/real(res,pReal)*real([i,j,k],pReal) & - geomdim/real(2_pInt*res,pReal) enddo; enddo; enddo @@ -80,6 +102,14 @@ module DAMASK_spectral_SolverAL trim(getSolverJobName()),size(F_lastInc)) read (777,rec=1) F_lastInc close (777) + call IO_read_jobBinaryFile(777,'convergedSpectralDefgradLambda',& + trim(getSolverJobName()),size(F_lambda)) + read (777,rec=1) F + close (777) + call IO_read_jobBinaryFile(777,'convergedSpectralDefgradLambda_lastInc',& + trim(getSolverJobName()),size(F_lambda_lastInc)) + 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) @@ -96,25 +126,51 @@ module DAMASK_spectral_SolverAL !-------------------------------------------------------------------------------------------------- ! reference stiffness if (restartInc == 1_pInt) then - C_ref = C - call IO_write_jobBinaryFile(777,'C_ref',size(C_ref)) - write (777,rec=1) C_ref + call IO_write_jobBinaryFile(777,'C_ref',size(C)) + write (777,rec=1) C close(777) elseif (restartInc > 1_pInt) then - call IO_read_jobBinaryFile(777,'C_ref',trim(getSolverJobName()),size(C_ref)) - read (777,rec=1) C_ref + call IO_read_jobBinaryFile(777,'C_ref',trim(getSolverJobName()),size(C)) + read (777,rec=1) C close (777) endif - call Utilities_Init(C_ref) + call Utilities_updateGamma(C_ref) + +!-------------------------------------------------------------------------------------------------- +! PETSc Init + call PetscInitialize(PETSC_NULL_CHARACTER,ierr_psc) + call MPI_Comm_rank(PETSC_COMM_WORLD,rank,ierr_psc) + + call SNESCreate(PETSC_COMM_WORLD,snes,ierr_psc) + call DMDACreate3d(PETSC_COMM_WORLD, & + DMDA_BOUNDARY_NONE, DMDA_BOUNDARY_NONE, DMDA_BOUNDARY_NONE, & + DMDA_STENCIL_BOX,res(1),res(2),res(3),PETSC_DECIDE,PETSC_DECIDE,PETSC_DECIDE, & + 18,1,PETSC_NULL_INTEGER,PETSC_NULL_INTEGER,PETSC_NULL_INTEGER,da,ierr_psc) + call DMCreateGlobalVector(da,x,ierr_psc) + call VecDuplicate(x,r,ierr_psc) + call DMDASetLocalFunction(da,FormFunctionLocal,ierr_psc) + + call SNESSetDM(snes,da,ierr_psc) + call SNESSetFunction(snes,r,SNESDMDAComputeFunction,da,ierr_psc) + call SNESSetConvergenceTest(snes,SNESConverged_Interactive,dummy,PETSC_NULL_FUNCTION,ierr_psc) + call PetscOptionsInsertString(PetSc_options,ierr_psc) + call SNESSetFromOptions(snes,ierr_psc) + call DMDAGetCorners(da,xs,ys,zs,xm,ym,zm,ierr_psc) + call DMDAGetCorners(da,gxs,gys,gzs,gxm,gym,gzm,ierr_psc) + + xs = xs+1; gxs = gxs+1; xm = xm-1; gxm = gxm-1 + ys = ys+1; gys = gys+1; ym = ym-1; gym = gym-1 + zs = zs+1; gzs = gzs+1; zm = zm-1; gzm = gzm-1 end subroutine AL_init type(solutionState) function AL_solution(guessmode,timeinc,timeinc_old,P_BC,F_BC,mask_stressVector,velgrad,rotation_BC) use numerics, only: & - itmax,& - itmin + itmax, & + itmin, & + update_gamma use IO, only: & IO_write_JobBinaryFile @@ -144,12 +200,12 @@ type(solutionState) function AL_solution(guessmode,timeinc,timeinc_old,P_BC,F_BC deltaF_aim, & F_aim_lab, & F_aim_lab_lastIter - real(pReal) :: err_div, err_stress - integer(pInt) :: iter integer(pInt) :: i, j, k logical :: ForwardData real(pReal) :: defgradDet real(pReal) :: defgradDetMax, defgradDetMin + + PetscScalar, pointer :: xx_psc(:) mask_stress = merge(ones,zeroes,reshape(mask_stressVector,[3,3])) mask_defgrad = merge(zeroes,ones,reshape(mask_stressVector,[3,3])) @@ -186,16 +242,27 @@ type(solutionState) function AL_solution(guessmode,timeinc,timeinc_old,P_BC,F_BC do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) temp33_Real = F(i,j,k,1:3,1:3) F(i,j,k,1:3,1:3) = F(i,j,k,1:3,1:3) & ! decide if guessing along former trajectory or apply homogeneous addon - + guessmode * (F(i,j,k,1:3,1:3) - F_lastInc(i,j,k,1:3,1:3))*timeinc/timeinc_old& ! guessing... - + (1.0_pReal-guessmode) * deltaF_aim ! if not guessing, use prescribed average deformation where applicable + + guessmode * (F(i,j,k,1:3,1:3) - F_lastInc(i,j,k,1:3,1:3))* & + timeinc/timeinc_old + (1.0_pReal-guessmode) * deltaF_aim ! if not guessing, use prescribed average deformation where applicable F_lastInc(i,j,k,1:3,1:3) = temp33_Real + temp33_Real = F_lambda(i,j,k,1:3,1:3) + F_lambda(i,j,k,1:3,1:3) = F_lambda(i,j,k,1:3,1:3) & ! decide if guessing along former trajectory or apply homogeneous addon + + guessmode * (F_lambda(i,j,k,1:3,1:3) - F_lambda_lastInc(i,j,k,1:3,1:3))* & + timeinc/timeinc_old + (1.0_pReal-guessmode) * deltaF_aim ! if not guessing, use prescribed average deformation where applicable + F_lambda_lastInc(i,j,k,1:3,1:3) = temp33_Real enddo; enddo; enddo call deformed_fft(res,geomdim,math_rotate_backward33(F_aim,rotation_BC),& ! calculate current coordinates 1.0_pReal,F_lastInc,coordinates) iter = 0_pInt - S = S_lastInc(rotation_BC,mask_stressVector,C) + S = Utilities_stressBC(rotation_BC,mask_stressVector,C) + if (update_gamma) call Utilities_updateGamma(C) + call VecGetArrayF90(x,xx_psc,ierr_psc) + call FormInitialGuessLocal(xx_psc) + call VecRestoreArrayF90(x,xx_psc,ierr_psc) + call SNESSolve(snes,PETSC_NULL_OBJECT,x,ierr_psc) + convergenceLoop: do while((iter < itmax .and. (any([err_div ,err_stress] > 1.0_pReal)))& .or. iter < itmin) @@ -218,21 +285,47 @@ type(solutionState) function AL_solution(guessmode,timeinc,timeinc_old,P_BC,F_BC !-------------------------------------------------------------------------------------------------- ! stress BC handling if(any(mask_stressVector)) then ! calculate stress BC if applied - err_stress = BCcorrection(mask_stressVector,P_BC,P_av,F_aim,S) + F_aim = F_aim - math_mul3333xx33(S, ((P_av - P_BC))) + err_stress = mask_stress * (P_av - P_BC))) else err_stress = 0.0_pReal endif - F_aim_lab = math_rotate_backward33(F_aim,rotation_BC) ! boundary conditions from load frame into lab (Fourier) frame + F_aim_lab = math_rotate_backward33(F_aim,rotation_BC) ! boundary conditions from load frame into lab (Fourier) frame !-------------------------------------------------------------------------------------------------- ! updated deformation gradient field_real(1:res(1),1:res(2),1:res(3),1:3,1:3) = P - err_div = convolution(.True.,F_aim_lab_lastIter - F_aim_lab, C_ref) + call FFT_forward() + err_div = calcDivergence() + call convolution_fourier(F_aim_lab_lastIter - F_aim_lab, C_ref) + call FFT_backward() do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) F(i,j,k,1:3,1:3) = F(i,j,k,1:3,1:3) - field_real(i,j,k,1:3,1:3) ! F(x)^(n+1) = F(x)^(n) + correction; *wgt: correcting for missing normalization enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! calculate some additional output + if(debugGeneral) then + maxCorrectionSkew = 0.0_pReal + maxCorrectionSym = 0.0_pReal + temp33_Real = 0.0_pReal + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + maxCorrectionSym = max(maxCorrectionSym,& + maxval(math_symmetric33(field_real(i,j,k,1:3,1:3)))) + maxCorrectionSkew = max(maxCorrectionSkew,& + maxval(math_skew33(field_real(i,j,k,1:3,1:3)))) + temp33_Real = temp33_Real + field_real(i,j,k,1:3,1:3) + enddo; enddo; enddo + write(6,'(a,1x,es11.4)') 'max symmetric correction of deformation =',& + maxCorrectionSym*wgt + write(6,'(a,1x,es11.4)') 'max skew correction of deformation =',& + maxCorrectionSkew*wgt + write(6,'(a,1x,es11.4)') 'max sym/skew of avg correction = ',& + maxval(math_symmetric33(temp33_real))/& + maxval(math_skew33(temp33_real)) + endif !-------------------------------------------------------------------------------------------------- ! calculate bounds of det(F) and report @@ -256,8 +349,226 @@ subroutine AL_destroy() implicit none +call VecDestroy(x,ierr_psc) +call VecDestroy(r,ierr_psc) +call SNESDestroy(snes,ierr_psc) +call DMDestroy(da,ierr_psc) +call PetscFinalize(ierr_psc) call Utilities_destroy() end subroutine AL_destroy +! ------------------------------------------------------------------- + +subroutine FormInitialGuessLocal(xx_psc) + + implicit none +#include + +! Input/output variables: + + PetscScalar xx_psc(0:17,gxs:(gxs+gxm),gys:(gys+gym),gxs:(gzs+gzm)) + integer(pInt) :: i, j, k + +! Compute function over the locally owned part of the grid + + do k=gzs,gzs+gzm; do j=gys,gys+gym; do i=gxs,gxs+gxm + xx_psc(0,i,j,k) = F(i,j,k,1,1) + xx_psc(1,i,j,k) = F(i,j,k,1,2) + xx_psc(2,i,j,k) = F(i,j,k,1,3) + xx_psc(3,i,j,k) = F(i,j,k,2,1) + xx_psc(4,i,j,k) = F(i,j,k,2,2) + xx_psc(5,i,j,k) = F(i,j,k,2,3) + xx_psc(6,i,j,k) = F(i,j,k,3,1) + xx_psc(7,i,j,k) = F(i,j,k,3,2) + xx_psc(8,i,j,k) = F(i,j,k,3,3) + xx_psc(9,i,j,k) = F_lambda(i,j,k,1,1) + xx_psc(10,i,j,k) = F_lambda(i,j,k,1,2) + xx_psc(11,i,j,k) = F_lambda(i,j,k,1,3) + xx_psc(12,i,j,k) = F_lambda(i,j,k,2,1) + xx_psc(13,i,j,k) = F_lambda(i,j,k,2,2) + xx_psc(14,i,j,k) = F_lambda(i,j,k,2,3) + xx_psc(15,i,j,k) = F_lambda(i,j,k,3,1) + xx_psc(16,i,j,k) = F_lambda(i,j,k,3,2) + xx_psc(17,i,j,k) = F_lambda(i,j,k,3,3) + enddo; enddo; enddo + + return +end subroutine FormInitialGuessLocal + +! --------------------------------------------------------------------- +! +! Input Parameter: +! x - local vector data +! +! Output Parameters: +! f - local vector data, f(x) +! ierr - error code +! +! Notes: +! This routine uses standard Fortran-style computations over a 3-dim array. +! +subroutine FormFunctionLocal(in,x_scal,f_scal,dummy,ierr_psc) + + use numerics, only: & + itmax, & + itmin + + implicit none +#include + +! Input/output variables: + DMDALocalInfo in(DMDA_LOCAL_INFO_SIZE) + PetscScalar x_scal(0:17,XG_RANGE,YG_RANGE,ZG_RANGE) + PetscScalar f_scal(0:17,X_RANGE,Y_RANGE,Z_RANGE) + real(pReal), dimension (3,3) :: temp + PetscObject dummy + +! Compute function over the locally owned part of the grid + + iter = iter + 1_pInt + +!-------------------------------------------------------------------------------------------------- +! report begin of new iteration + write(6,'(a)') '' + write(6,'(a)') '==================================================================' + write(6,'(3(a,i6.6))') ' @ Iter. ',itmin,' < ',iter,' < ',itmax + write(6,'(a,/,3(3(f12.7,1x)/))',advance='no') 'deformation gradient aim =',& + math_transpose33(F_aim) + + F_star_av = 0.0 + lambda_av = 0.0 + do k=gzs,gze; do j=gys,gye; do i=gxs,gxe + F(i,j,k,1,1) = x_scal(0,i,j,k) + F(i,j,k,1,2) = x_scal(1,i,j,k) + F(i,j,k,1,3) = x_scal(2,i,j,k) + F(i,j,k,2,1) = x_scal(3,i,j,k) + F(i,j,k,2,2) = x_scal(4,i,j,k) + F(i,j,k,2,3) = x_scal(5,i,j,k) + F(i,j,k,3,1) = x_scal(6,i,j,k) + F(i,j,k,3,2) = x_scal(7,i,j,k) + F(i,j,k,3,3) = x_scal(8,i,j,k) + F_lambda(i,j,k,1,1) = x_scal(9,i,j,k) + F_lambda(i,j,k,1,2) = x_scal(10,i,j,k) + F_lambda(i,j,k,1,3) = x_scal(11,i,j,k) + F_lambda(i,j,k,2,1) = x_scal(12,i,j,k) + F_lambda(i,j,k,2,2) = x_scal(13,i,j,k) + F_lambda(i,j,k,2,3) = x_scal(14,i,j,k) + F_lambda(i,j,k,3,1) = x_scal(15,i,j,k) + F_lambda(i,j,k,3,2) = x_scal(16,i,j,k) + F_lambda(i,j,k,3,3) = x_scal(17,i,j,k) + F_star_av = F_star_av + F(i,j,k,1:3,1:3) + lambda_av = lambda_av + F_lambda(i,j,k,1:3,1:3) + enddo; enddo; enddo + F_star_av = F_star_av *wgt + lambda_av = math_mul3333xx33(C_inc0,lambda_av*wgt-math_I3) + +!-------------------------------------------------------------------------------------------------- +! evaluate constitutive response + call constitutiveResponse(coordinates,F,F_lastInc,temperature,timeinc,& + P,C,P_av,ForwardData,rotation_BC) + ForwardData = .False. + +!-------------------------------------------------------------------------------------------------- +! stress BC handling + if(any(mask_stressVector)) then ! calculate stress BC if applied + F_aim = F_aim - math_mul3333xx33(S, ((P_av - P_BC))) + err_stress = mask_stress * (P_av - P_BC))) + else + err_stress = 0.0_pReal + endif + + F_aim_lab = math_rotate_backward33(F_aim,rotation_BC) + +!-------------------------------------------------------------------------------------------------- +! doing Fourier transform + field_real = 0.0_pReal + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + field_real(i,j,k,1:3,1:3) = math_mul3333xx33(C_ref,F_lambda(i,j,k,1:3,1:3)-F(i,j,k,1:3,1:3)) + + enddo; enddo; enddo + + call Utilities_forwardFFT() + call Utilities_fourierConvolution(F_aim_lab) + call Utilities_backwardFFT() + + err_f = 0.0_pReal + err_f_point = 0.0_pReal + err_p = 0.0_pReal + err_p_point = 0.0_pReal + + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + temp33_real = field_real(i,j,k,1:3,1:3) - F(i,j,k,1:3,1:3) + err_f_point = max(err_f_point, maxval(abs(temp33_real))) + err_f = err_f + sum(temp33_real*temp33_real) + + temp33_real = F_lambda(i,j,k,1:3,1:3) - & + math_mul3333xx33(S_inc0,P(i,j,k,1:3,1:3)) + math_I3 + err_p_point = max(err_p_point, maxval(abs(temp33_real))) + err_p = err_p + sum(temp33_real*temp33_real) + enddo; enddo; enddo + + err_f = wgt*sqrt(err_f/sum((F_aim-math_I3)*(F_aim-math_I3))) + err_p = wgt*sqrt(err_p/sum((F_aim-math_I3)*(F_aim-math_I3))) + + write(6,'(a,es14.7,es14.7)') 'error stress = ',err_stress/err_stress_tol + write(6,*) ' ' + write(6,'(a,es14.7)') 'max abs err F', err_f + write(6,'(a,es14.7)') 'max abs err P', err_p + + do k=zs,ze; do j=ys,ye; do i=xs,xe + temp = math_mul3333xx33(S_inc0,P(i,j,k,1:3,1:3)) + math_I3 - F_lambda(i,j,k,1:3,1:3) & + + F(i,j,k,1:3,1:3) - field_real(i,j,k,1:3,1:3) + f_scal(0,i,j,k) = temp(1,1) + f_scal(1,i,j,k) = temp(1,2) + f_scal(2,i,j,k) = temp(1,3) + f_scal(3,i,j,k) = temp(2,1) + f_scal(4,i,j,k) = temp(2,2) + f_scal(5,i,j,k) = temp(2,3) + f_scal(6,i,j,k) = temp(3,1) + f_scal(7,i,j,k) = temp(3,2) + f_scal(8,i,j,k) = temp(3,3) + f_scal(9,i,j,k) = F(i,j,k,1,1) - field_real(i,j,k,1,1) + f_scal(10,i,j,k) = F(i,j,k,1,2) - field_real(i,j,k,1,2) + f_scal(11,i,j,k) = F(i,j,k,1,3) - field_real(i,j,k,1,3) + f_scal(12,i,j,k) = F(i,j,k,2,1) - field_real(i,j,k,2,1) + f_scal(13,i,j,k) = F(i,j,k,2,2) - field_real(i,j,k,2,2) + f_scal(14,i,j,k) = F(i,j,k,2,3) - field_real(i,j,k,2,3) + f_scal(15,i,j,k) = F(i,j,k,3,1) - field_real(i,j,k,3,1) + f_scal(16,i,j,k) = F(i,j,k,3,2) - field_real(i,j,k,3,2) + f_scal(17,i,j,k) = F(i,j,k,3,3) - field_real(i,j,k,3,3) + enddo; enddo; enddo + + return +end subroutine FormFunctionLocal + +! --------------------------------------------------------------------- +! User defined convergence check +! +subroutine SNESConverged_Interactive(snes,it,xnorm,snorm,fnorm,reason,dummy,ierr_psc) + + implicit none +#include + +! Input/output variables: + SNES snes + PetscInt it + PetscReal xnorm, snorm, fnorm + SNESConvergedReason reason + PetscObject dummy + PetscErrorCode ierr_psc + + err_crit = max(err_stress/err_stress_tol, & + err_f/1e-6, err_p/1e-5) + !fnorm*wgt/sqrt(sum((F_star_av-math_I3)*(F_star_av-math_I3)))/err_div_tol) + + if ((err_crit > 1.0_pReal .or. it < itmin) .and. it < itmax) then + reason = 0 + else + reason = 1 + endif + + return +end subroutine SNESConverged_Interactive + end module DAMASK_spectral_SolverAL diff --git a/code/DAMASK_spectral_SolverBasic.f90 b/code/DAMASK_spectral_SolverBasic.f90 index 51fb14a8d..53fdba661 100644 --- a/code/DAMASK_spectral_SolverBasic.f90 +++ b/code/DAMASK_spectral_SolverBasic.f90 @@ -12,6 +12,8 @@ module DAMASK_spectral_SolverBasic implicit none + real(pReal), dimension(3,3) :: temp33_Real + character (len=*), parameter, public :: & DAMASK_spectral_SolverBasic_label = 'basic' @@ -25,10 +27,9 @@ module DAMASK_spectral_SolverBasic ! stress, stiffness and compliance average etc. real(pReal), dimension(3,3) :: & F_aim = math_I3, & - F_aim_lastInc = math_I3, & - P_av + F_aim_lastInc = math_I3 + real(pReal), dimension(3,3,3,3) :: & - C_ref = 0.0_pReal, & C = 0.0_pReal @@ -49,8 +50,7 @@ module DAMASK_spectral_SolverBasic implicit none integer(pInt) :: i,j,k - res = mesh_spectral_getResolution() - geomdim = mesh_spectral_getDimension() + call Utilities_Init() allocate (F ( res(1), res(2),res(3),3,3), source = 0.0_pReal) allocate (F_lastInc ( res(1), res(2),res(3),3,3), source = 0.0_pReal) @@ -88,31 +88,31 @@ module DAMASK_spectral_SolverBasic coordinates = 0.0 ! change it later!!! endif - call constitutiveResponse(coordinates,F,F_lastInc,temperature,0.0_pReal,& - P,C,P_av,.false.,math_I3) + call Utilities_constitutiveResponse(coordinates,F,F_lastInc,temperature,0.0_pReal,& + P,C,temp33_Real,.false.,math_I3) !-------------------------------------------------------------------------------------------------- ! reference stiffness if (restartInc == 1_pInt) then - C_ref = C - call IO_write_jobBinaryFile(777,'C_ref',size(C_ref)) - write (777,rec=1) C_ref + call IO_write_jobBinaryFile(777,'C_ref',size(C)) + write (777,rec=1) C close(777) elseif (restartInc > 1_pInt) then - call IO_read_jobBinaryFile(777,'C_ref',trim(getSolverJobName()),size(C_ref)) - read (777,rec=1) C_ref + call IO_read_jobBinaryFile(777,'C_ref',trim(getSolverJobName()),size(C)) + read (777,rec=1) C close (777) endif - call Utilities_Init(C_ref) + call Utilities_updateGamma(C) end subroutine basic_init type(solutionState) function basic_solution(guessmode,timeinc,timeinc_old,P_BC,F_BC,mask_stressVector,velgrad,rotation_BC) use numerics, only: & - itmax,& - itmin + itmax, & + itmin, & + update_gamma use IO, only: & IO_write_JobBinaryFile @@ -141,7 +141,8 @@ type(solutionState) function basic_solution(guessmode,timeinc,timeinc_old,P_BC,F mask_defgrad, & deltaF_aim, & F_aim_lab, & - F_aim_lab_lastIter + F_aim_lab_lastIter, & + P_av real(pReal) :: err_div, err_stress integer(pInt) :: iter integer(pInt) :: i, j, k @@ -192,10 +193,10 @@ type(solutionState) function basic_solution(guessmode,timeinc,timeinc_old,P_BC,F 1.0_pReal,F_lastInc,coordinates) iter = 0_pInt - S = S_lastInc(rotation_BC,mask_stressVector,C) - - convergenceLoop: do while((iter < itmax .and. (any([err_div ,err_stress] > 1.0_pReal)))& - .or. iter < itmin) + S = Utilities_stressBC(rotation_BC,mask_stressVector,C) + if (update_gamma) call Utilities_updateGamma(C) + + convergenceLoop: do while(.not. basic_convergenced(err_div,P_av,err_stress,P_av,iter)) iter = iter + 1_pInt !-------------------------------------------------------------------------------------------------- @@ -209,14 +210,15 @@ type(solutionState) function basic_solution(guessmode,timeinc,timeinc_old,P_BC,F !-------------------------------------------------------------------------------------------------- ! evaluate constitutive response - call constitutiveResponse(coordinates,F,F_lastInc,temperature,timeinc,& + call Utilities_constitutiveResponse(coordinates,F,F_lastInc,temperature,timeinc,& P,C,P_av,ForwardData,rotation_BC) ForwardData = .False. !-------------------------------------------------------------------------------------------------- ! stress BC handling if(any(mask_stressVector)) then ! calculate stress BC if applied - err_stress = BCcorrection(mask_stressVector,P_BC,P_av,F_aim,S) + F_aim = F_aim - math_mul3333xx33(S, ((P_av - P_BC))) + err_stress = mask_stress * (P_av - P_BC))) else err_stress = 0.0_pReal endif @@ -226,11 +228,36 @@ type(solutionState) function basic_solution(guessmode,timeinc,timeinc_old,P_BC,F !-------------------------------------------------------------------------------------------------- ! updated deformation gradient field_real(1:res(1),1:res(2),1:res(3),1:3,1:3) = P - err_div = convolution(.True.,F_aim_lab_lastIter - F_aim_lab, C_ref) + call Utilities_forwardFFT() + err_div = Utilities_divergenceRMS() + call Utilities_fourierConvolution(F_aim_lab_lastIter - F_aim_lab) + call Utilities_backwardFFT() do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) F(i,j,k,1:3,1:3) = F(i,j,k,1:3,1:3) - field_real(i,j,k,1:3,1:3) ! F(x)^(n+1) = F(x)^(n) + correction; *wgt: correcting for missing normalization enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! calculate some additional output + if(debugGeneral) then + maxCorrectionSkew = 0.0_pReal + maxCorrectionSym = 0.0_pReal + temp33_Real = 0.0_pReal + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + maxCorrectionSym = max(maxCorrectionSym,& + maxval(math_symmetric33(field_real(i,j,k,1:3,1:3)))) + maxCorrectionSkew = max(maxCorrectionSkew,& + maxval(math_skew33(field_real(i,j,k,1:3,1:3)))) + temp33_Real = temp33_Real + field_real(i,j,k,1:3,1:3) + enddo; enddo; enddo + write(6,'(a,1x,es11.4)') 'max symmetric correction of deformation =',& + maxCorrectionSym*wgt + write(6,'(a,1x,es11.4)') 'max skew correction of deformation =',& + maxCorrectionSkew*wgt + write(6,'(a,1x,es11.4)') 'max sym/skew of avg correction = ',& + maxval(math_symmetric33(temp33_real))/& + maxval(math_skew33(temp33_real)) + endif !-------------------------------------------------------------------------------------------------- ! calculate bounds of det(F) and report @@ -246,10 +273,35 @@ type(solutionState) function basic_solution(guessmode,timeinc,timeinc_old,P_BC,F write(6,'(a,1x,es11.4)') 'max determinant of deformation =', defgradDetMax write(6,'(a,1x,es11.4)') 'min determinant of deformation =', defgradDetMin endif + enddo convergenceLoop end function basic_solution +logical function basic_convergenced(err_div,P_av,err_stress,P_av,iter) + + use numerics, only: & + itmax, & + itmin, & + err_div_tol, & + err_stress_tolrel, & + err_stress_tolabs + + implicit none + + real(pReal), dimension(3,3) :: P_av + real(pReal) :: err_div, err_stress, field_av_L2 + integer(pInt) :: iter + + field_av_L2 = sqrt(maxval(math_eigenvalues33(math_mul33x33(P_av,& ! L_2 norm of average stress (http://mathworld.wolfram.com/SpectralNorm.html) + math_transpose33(P_av))))) + basic_convergenced = (iter < itmax) .and. (iter > itmin) .and. & + (err_div/field_av_L2/err_div_tol < 1.0_pReal) .and. & + (err_stress/min(maxval(abs(P_av))*err_stress_tolrel,err_stress_tolabs) < 1.0_pReal) + + +end function basic_convergenced + subroutine basic_destroy() implicit none diff --git a/code/DAMASK_spectral_Utilities.f90 b/code/DAMASK_spectral_Utilities.f90 index 735498286..14dfa7e89 100644 --- a/code/DAMASK_spectral_Utilities.f90 +++ b/code/DAMASK_spectral_Utilities.f90 @@ -51,6 +51,7 @@ module DAMASK_spectral_Utilities ! variables storing information for spectral method and FFTW type(C_PTR) :: plan_forward, plan_backward ! plans for fftw real(pReal), dimension(:,:,:,:,:,:,:), allocatable :: gamma_hat ! gamma operator (field) for spectral method + real(pReal), dimension(3,3,3,3) :: C_ref real(pReal), dimension(:,:,:,:), allocatable :: xi ! wave vector field for divergence and for gamma operator real(pReal), dimension(:,:,:,:,:), pointer :: field_real complex(pReal), dimension(:,:,:,:,:), pointer :: field_fourier @@ -87,7 +88,7 @@ module DAMASK_spectral_Utilities end type solutionState contains -subroutine Utilities_init(C_ref) +subroutine Utilities_init() use mesh, only : & mesh_spectral_getResolution, & @@ -106,17 +107,11 @@ subroutine Utilities_init(C_ref) debug_spectralDivergence, & debug_spectralRestart, & debug_spectralFFTW - - use numerics, only: & - memory_efficient implicit none - real(pReal), dimension(3,3) :: temp33_Real, xiDyad - integer(pInt) :: i, j, k, l, m, n, q, ierr + integer(pInt) :: i, j, k, ierr integer(pInt), dimension(3) :: k_s - real(pReal), dimension(3,3,3,3) :: & - C_ref type(C_PTR) :: tensorField ! field in real and fourier space type(C_PTR) :: scalarField_realC, scalarField_fourierC @@ -225,69 +220,63 @@ subroutine Utilities_init(C_ref) if(memory_efficient) then ! allocate just single fourth order tensor allocate (gamma_hat(1,1,1,3,3,3,3), source = 0.0_pReal) else ! precalculation of gamma_hat field - allocate (gamma_hat(res1_red ,res(2),res(3),3,3,3,3), source =0.0_pReal) - do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res1_red - if(any([i,j,k] /= 1_pInt)) then ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - xiDyad(l,m) = xi(l, i,j,k)*xi(m, i,j,k) - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - temp33_Real(l,m) = sum(C_ref(l,m,1:3,1:3)*xiDyad) - temp33_Real = math_inv33(temp33_Real) - forall(l=1_pInt:3_pInt, m=1_pInt:3_pInt, n=1_pInt:3_pInt, q=1_pInt:3_pInt)& - gamma_hat(i,j,k, l,m,n,q) = temp33_Real(l,n)*xiDyad(m,q) - endif - enddo; enddo; enddo - gamma_hat(1,1,1, 1:3,1:3,1:3,1:3) = 0.0_pReal ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 + allocate (gamma_hat(res1_red ,res(2),res(3),3,3,3,3), source =0.0_pReal) ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 endif end subroutine Utilities_init - -real(pReal) function convolution(calcDivergence,field_aim,C_ref) - + +subroutine Utilities_updateGamma(C) + use numerics, only: & - memory_efficient, & - err_div_tol + memory_efficient - real(pReal), dimension(3,3) :: xiDyad ! product of wave vectors - real(pReal) :: err_div = 0.0_pReal - real(pReal), dimension(3,3) :: temp33_Real + implicit none + + real(pReal), dimension(3,3,3,3) :: C + real(pReal), dimension(3,3) :: temp33_Real, xiDyad integer(pInt) :: i, j, k, l, m, n, q - real(pReal), dimension(3,3,3,3) :: C_ref - -!-------------------------------------------------------------------------------------------------- -!variables for additional output due to general debugging - real(pReal) :: maxCorrectionSym, maxCorrectionSkew - logical :: calcDivergence - real(pReal), dimension(3,3) :: field_avg, field_aim - integer(pInt) :: row, column - real(pReal) :: field_av_L2, err_div_RMS, err_real_div_RMS, err_post_div_RMS,& - err_div_max, err_real_div_max - complex(pReal), dimension(3) :: temp3_complex - complex(pReal), dimension(3,3) :: temp33_complex -!-------------------------------------------------------------------------------------------------- -! actual spectral method - write(6,'(a)') '' - write(6,'(a)') '... doing convolution .................' + C_ref = C + if(.not. memory_efficient) then + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res1_red + if(any([i,j,k] /= 1_pInt)) then ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + xiDyad(l,m) = xi(l, i,j,k)*xi(m, i,j,k) + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + temp33_Real(l,m) = sum(C_ref(l,m,1:3,1:3)*xiDyad) + temp33_Real = math_inv33(temp33_Real) + forall(l=1_pInt:3_pInt, m=1_pInt:3_pInt, n=1_pInt:3_pInt, q=1_pInt:3_pInt)& + gamma_hat(i,j,k, l,m,n,q) = temp33_Real(l,n)*xiDyad(m,q) + endif + enddo; enddo; enddo + gamma_hat(1,1,1, 1:3,1:3,1:3,1:3) = 0.0_pReal ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 + endif + +end subroutine Utilities_updateGamma + +subroutine Utilities_forwardFFT() + + implicit none + + integer(pInt) :: row, column + !-------------------------------------------------------------------------------------------------- ! copy one component of the stress field to to a single FT and check for mismatch if (debugFFTW) then - row = 3 ! (mod(totalIncsCounter+iter-2_pInt,9_pInt))/3_pInt + 1_pInt ! go through the elements of the tensors, controlled by totalIncsCounter and iter, starting at 1 - column = 3 !(mod(totalIncsCounter+iter-2_pInt,3_pInt)) + 1_pInt scalarField_real(1:res(1),1:res(2),1:res(3)) =& ! store the selected component cmplx(field_real(1:res(1),1:res(2),1:res(3),row,column),0.0_pReal,pReal) + endif - + !-------------------------------------------------------------------------------------------------- ! call function to calculate divergence from math (for post processing) to check results if (debugDivergence) & call divergence_fft(res,virt_dim,3_pInt,& - field_real(1:res(1),1:res(2),1:res(3),1:3,1:3),divergence_post) ! padding - + field_real(1:res(1),1:res(2),1:res(3),1:3,1:3),divergence_post) + !-------------------------------------------------------------------------------------------------- ! doing the FT because it simplifies calculation of average stress in real space also call fftw_execute_dft_r2c(plan_forward,field_real,field_fourier) - - + !-------------------------------------------------------------------------------------------------- ! comparing 1 and 3x3 FT results if (debugFFTW) then @@ -302,115 +291,19 @@ real(pReal) function convolution(calcDivergence,field_aim,C_ref) scalarField_fourier(1:res1_red,1:res(2),1:res(3)))) endif -!-------------------------------------------------------------------------------------------------- -! removing highest frequencies - field_fourier ( res1_red,1:res(2) , 1:res(3) ,1:3,1:3)& - = cmplx(0.0_pReal,0.0_pReal,pReal) - field_fourier (1:res1_red, res(2)/2_pInt+1_pInt,1:res(3) ,1:3,1:3)& - = cmplx(0.0_pReal,0.0_pReal,pReal) - if(res(3)>1_pInt) & - field_fourier (1:res1_red,1:res(2), res(3)/2_pInt+1_pInt,1:3,1:3)& - = cmplx(0.0_pReal,0.0_pReal,pReal) +end subroutine Utilities_forwardFFT +subroutine Utilities_backwardFFT() -!-------------------------------------------------------------------------------------------------- -! calculating RMS divergence criterion in Fourier space - if(calcDivergence) then - field_avg = real(field_fourier(1,1,1,1:3,1:3),pReal)*wgt + implicit none - field_av_L2 = sqrt(maxval(math_eigenvalues33(math_mul33x33(field_avg,& ! L_2 norm of average stress (http://mathworld.wolfram.com/SpectralNorm.html) - math_transpose33(field_avg))))) - err_div_RMS = 0.0_pReal - do k = 1_pInt, res(3); do j = 1_pInt, res(2) - do i = 2_pInt, res1_red -1_pInt ! Has somewhere a conj. complex counterpart. Therefore count it twice. - err_div_RMS = err_div_RMS & - + 2.0_pReal*(sum (real(math_mul33x3_complex(field_fourier(i,j,k,1:3,1:3),& ! (sqrt(real(a)**2 + aimag(a)**2))**2 = real(a)**2 + aimag(a)**2. do not take square root and square again - xi(1:3,i,j,k))*TWOPIIMG)**2.0_pReal)& ! --> sum squared L_2 norm of vector - +sum(aimag(math_mul33x3_complex(field_fourier(i,j,k,1:3,1:3),& - xi(1:3,i,j,k))*TWOPIIMG)**2.0_pReal)) - enddo - err_div_RMS = err_div_RMS & ! Those two layers (DC and Nyquist) do not have a conjugate complex counterpart - + sum( real(math_mul33x3_complex(field_fourier(1 ,j,k,1:3,1:3),& - xi(1:3,1 ,j,k))*TWOPIIMG)**2.0_pReal)& - + sum(aimag(math_mul33x3_complex(field_fourier(1 ,j,k,1:3,1:3),& - xi(1:3,1 ,j,k))*TWOPIIMG)**2.0_pReal)& - + sum( real(math_mul33x3_complex(field_fourier(res1_red,j,k,1:3,1:3),& - xi(1:3,res1_red,j,k))*TWOPIIMG)**2.0_pReal)& - + sum(aimag(math_mul33x3_complex(field_fourier(res1_red,j,k,1:3,1:3),& - xi(1:3,res1_red,j,k))*TWOPIIMG)**2.0_pReal) - enddo; enddo + integer(pInt) :: row, column, i, j, k, m, n - err_div_RMS = sqrt(err_div_RMS)*wgt ! RMS in real space calculated with Parsevals theorem from Fourier space - err_div = err_div_RMS/field_av_L2 ! criterion to stop iterations - - -!-------------------------------------------------------------------------------------------------- -! calculate additional divergence criteria and report - if (debugDivergence) then ! calculate divergence again - err_div_max = 0.0_pReal - do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res1_red - temp3_Complex = math_mul33x3_complex(field_fourier(i,j,k,1:3,1:3)*wgt,& ! weighting P_fourier - xi(1:3,i,j,k))*TWOPIIMG - err_div_max = max(err_div_max,sum(abs(temp3_Complex)**2.0_pReal)) - divergence_fourier(i,j,k,1:3) = temp3_Complex ! need divergence NOT squared - enddo; enddo; enddo - - call fftw_execute_dft_c2r(plan_divergence,divergence_fourier,divergence_real) ! already weighted - - err_real_div_RMS = 0.0_pReal - err_post_div_RMS = 0.0_pReal - err_real_div_max = 0.0_pReal - do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) - err_real_div_RMS = err_real_div_RMS + sum(divergence_real(i,j,k,1:3)**2.0_pReal) ! avg of squared L_2 norm of div(stress) in real space - err_post_div_RMS = err_post_div_RMS + sum(divergence_post(i,j,k,1:3)**2.0_pReal) ! avg of squared L_2 norm of div(stress) in real space - err_real_div_max = max(err_real_div_max,sum(divergence_real(i,j,k,1:3)**2.0_pReal)) ! max of squared L_2 norm of div(stress) in real space - enddo; enddo; enddo - - err_real_div_RMS = sqrt(wgt*err_real_div_RMS) ! RMS in real space - err_post_div_RMS = sqrt(wgt*err_post_div_RMS) ! RMS in real space - err_real_div_max = sqrt( err_real_div_max) ! max in real space - err_div_max = sqrt( err_div_max) ! max in Fourier space - - write(6,'(a,es11.4)') 'error divergence FT RMS = ',err_div_RMS - write(6,'(a,es11.4)') 'error divergence Real RMS = ',err_real_div_RMS - write(6,'(a,es11.4)') 'error divergence post RMS = ',err_post_div_RMS - write(6,'(a,es11.4)') 'error divergence FT max = ',err_div_max - write(6,'(a,es11.4)') 'error divergence Real max = ',err_real_div_max - endif - write(6,'(a,f6.2,a,es11.4,a)') 'error divergence = ', err_div/err_div_tol,& - ' (',err_div,' N/m³)' - end if -!-------------------------------------------------------------------------------------------------- -! to the actual spectral method calculation (mechanical equilibrium) - if(memory_efficient) then ! memory saving version, on-the-fly calculation of gamma_hat - do k = 1_pInt, res(3); do j = 1_pInt, res(2) ;do i = 1_pInt, res1_red - if(any([i,j,k] /= 1_pInt)) then ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - xiDyad(l,m) = xi(l, i,j,k)*xi(m, i,j,k) - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - temp33_Real(l,m) = sum(C_ref(l,m,1:3,1:3)*xiDyad) - temp33_Real = math_inv33(temp33_Real) - forall(l=1_pInt:3_pInt, m=1_pInt:3_pInt, n=1_pInt:3_pInt, q=1_pInt:3_pInt)& - gamma_hat(1,1,1, l,m,n,q) = temp33_Real(l,n)*xiDyad(m,q) - forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - temp33_Complex(l,m) = sum(gamma_hat(1,1,1, l,m, 1:3,1:3) *& - field_fourier(i,j,k,1:3,1:3)) - field_fourier(i,j,k,1:3,1:3) = temp33_Complex - endif - enddo; enddo; enddo - else ! use precalculated gamma-operator - do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt,res1_red - forall( m = 1_pInt:3_pInt, n = 1_pInt:3_pInt) & - temp33_Complex(m,n) = sum(gamma_hat(i,j,k, m,n, 1:3,1:3) *& - field_fourier(i,j,k,1:3,1:3)) - field_fourier(i,j,k, 1:3,1:3) = temp33_Complex - enddo; enddo; enddo - endif - field_fourier(1,1,1,1:3,1:3) = cmplx(field_aim,0.0_pReal,pReal) ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 - !-------------------------------------------------------------------------------------------------- ! comparing 1 and 3x3 inverse FT results if (debugFFTW) then + row = 3 ! (mod(totalIncsCounter+iter-2_pInt,9_pInt))/3_pInt + 1_pInt ! go through the elements of the tensors, controlled by totalIncsCounter and iter, starting at 1 + column = 3 !(mod(totalIncsCounter+iter-2_pInt,3_pInt)) + 1_pInt do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res1_red scalarField_fourier(i,j,k) = field_fourier(i,j,k,row,column) enddo; enddo; enddo @@ -442,115 +335,192 @@ real(pReal) function convolution(calcDivergence,field_aim,C_ref) real(scalarField_real(1:res(1),1:res(2),1:res(3)))) endif +end subroutine Utilities_backwardFFT + +subroutine Utilities_fourierConvolution(field_aim) + + use numerics, only: & + memory_efficient + + implicit none + + real(pReal), dimension(3,3) :: xiDyad, temp33_Real, field_aim + integer(pInt) :: i, j, k, l, m, n, q + complex(pReal), dimension(3,3) :: temp33_complex + !-------------------------------------------------------------------------------------------------- -! calculate some additional output - if(debugGeneral) then - maxCorrectionSkew = 0.0_pReal - maxCorrectionSym = 0.0_pReal - temp33_Real = 0.0_pReal - do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) - maxCorrectionSym = max(maxCorrectionSym,& - maxval(math_symmetric33(field_real(i,j,k,1:3,1:3)))) - maxCorrectionSkew = max(maxCorrectionSkew,& - maxval(math_skew33(field_real(i,j,k,1:3,1:3)))) - temp33_Real = temp33_Real + field_real(i,j,k,1:3,1:3) +! actual spectral method + write(6,'(a)') '' + write(6,'(a)') '... doing convolution .................' + +!-------------------------------------------------------------------------------------------------- +! removing highest frequencies + field_fourier ( res1_red,1:res(2) , 1:res(3) ,1:3,1:3)& + = cmplx(0.0_pReal,0.0_pReal,pReal) + field_fourier (1:res1_red, res(2)/2_pInt+1_pInt,1:res(3) ,1:3,1:3)& + = cmplx(0.0_pReal,0.0_pReal,pReal) + if(res(3)>1_pInt) & + field_fourier (1:res1_red,1:res(2), res(3)/2_pInt+1_pInt,1:3,1:3)& + = cmplx(0.0_pReal,0.0_pReal,pReal) + +!-------------------------------------------------------------------------------------------------- +! to the actual spectral method calculation (mechanical equilibrium) + if(memory_efficient) then ! memory saving version, on-the-fly calculation of gamma_hat + do k = 1_pInt, res(3); do j = 1_pInt, res(2) ;do i = 1_pInt, res1_red + if(any([i,j,k] /= 1_pInt)) then ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + xiDyad(l,m) = xi(l, i,j,k)*xi(m, i,j,k) + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + temp33_Real(l,m) = sum(C_ref(l,m,1:3,1:3)*xiDyad) + temp33_Real = math_inv33(temp33_Real) + forall(l=1_pInt:3_pInt, m=1_pInt:3_pInt, n=1_pInt:3_pInt, q=1_pInt:3_pInt)& + gamma_hat(1,1,1, l,m,n,q) = temp33_Real(l,n)*xiDyad(m,q) + forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & + temp33_Complex(l,m) = sum(gamma_hat(1,1,1, l,m, 1:3,1:3) *& + field_fourier(i,j,k,1:3,1:3)) + field_fourier(i,j,k,1:3,1:3) = temp33_Complex + endif + enddo; enddo; enddo + else ! use precalculated gamma-operator + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt,res1_red + forall( m = 1_pInt:3_pInt, n = 1_pInt:3_pInt) & + temp33_Complex(m,n) = sum(gamma_hat(i,j,k, m,n, 1:3,1:3) *& + field_fourier(i,j,k,1:3,1:3)) + field_fourier(i,j,k, 1:3,1:3) = temp33_Complex enddo; enddo; enddo - write(6,'(a,1x,es11.4)') 'max symmetric correction of deformation =',& - maxCorrectionSym*wgt - write(6,'(a,1x,es11.4)') 'max skew correction of deformation =',& - maxCorrectionSkew*wgt - write(6,'(a,1x,es11.4)') 'max sym/skew of avg correction = ',& - maxval(math_symmetric33(temp33_real))/& - maxval(math_skew33(temp33_real)) endif - field_real = field_real * wgt - convolution = err_div/err_div_tol + field_fourier(1,1,1,1:3,1:3) = cmplx(field_aim,0.0_pReal,pReal) ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 -end function convolution - - -function S_lastInc(rot_BC,mask_stressVector1,C) +end subroutine Utilities_fourierConvolution - real(pReal), dimension(3,3,3,3) :: S_lastInc - real(pReal), dimension(3,3,3,3), intent(in) :: C - integer(pInt) :: i, j, k, m, n - real(pReal), dimension(3,3), intent(in) :: rot_BC - logical, dimension(9), intent(in) :: mask_stressVector1 - real(pReal), dimension(3,3,3,3) :: C_lastInc - real(pReal), dimension(9,9) :: temp99_Real - integer(pInt) :: size_reduced = 0_pInt - real(pReal), dimension(:,:), allocatable :: s_reduced, c_reduced ! reduced compliance and stiffness (only for stress BC) - logical :: errmatinv - size_reduced = count(mask_stressVector1) - allocate (c_reduced(size_reduced,size_reduced), source =0.0_pReal) - allocate (s_reduced(size_reduced,size_reduced), source =0.0_pReal) +real(pReal) function Utilities_divergenceRMS() + + use numerics, only: err_div_tol + + integer(pInt) :: i, j, k, l, m, n, q + +!-------------------------------------------------------------------------------------------------- +!variables for additional output due to general debugging + real(pReal), dimension(3,3) :: field_avg + real(pReal) :: field_av_L2, err_div_RMS, err_real_div_RMS, err_post_div_RMS,& + err_div_max, err_real_div_max + complex(pReal), dimension(3) :: temp3_complex + +!-------------------------------------------------------------------------------------------------- +! actual spectral method + write(6,'(a)') '' + write(6,'(a)') '... calculating divergence .................' - C_lastInc = math_rotate_forward3333(C,rot_BC) ! calculate stiffness from former inc - temp99_Real = math_Plain3333to99(C_lastInc) - k = 0_pInt ! build reduced stiffness - do n = 1_pInt,9_pInt - if(mask_stressVector1(n)) then - k = k + 1_pInt - j = 0_pInt - do m = 1_pInt,9_pInt - if(mask_stressVector1(m)) then - j = j + 1_pInt - c_reduced(k,j) = temp99_Real(n,m) - endif; enddo; endif; enddo - call math_invert(size_reduced, c_reduced, s_reduced, i, errmatinv) ! invert reduced stiffness - if(errmatinv) call IO_error(error_ID=400_pInt) - temp99_Real = 0.0_pReal ! build full compliance - k = 0_pInt +!-------------------------------------------------------------------------------------------------- +! calculating RMS divergence criterion in Fourier space + + err_div_RMS = 0.0_pReal + do k = 1_pInt, res(3); do j = 1_pInt, res(2) + do i = 2_pInt, res1_red -1_pInt ! Has somewhere a conj. complex counterpart. Therefore count it twice. + err_div_RMS = err_div_RMS & + + 2.0_pReal*(sum (real(math_mul33x3_complex(field_fourier(i,j,k,1:3,1:3),& ! (sqrt(real(a)**2 + aimag(a)**2))**2 = real(a)**2 + aimag(a)**2. do not take square root and square again + xi(1:3,i,j,k))*TWOPIIMG)**2.0_pReal)& ! --> sum squared L_2 norm of vector + +sum(aimag(math_mul33x3_complex(field_fourier(i,j,k,1:3,1:3),& + xi(1:3,i,j,k))*TWOPIIMG)**2.0_pReal)) + enddo + err_div_RMS = err_div_RMS & ! Those two layers (DC and Nyquist) do not have a conjugate complex counterpart + + sum( real(math_mul33x3_complex(field_fourier(1 ,j,k,1:3,1:3),& + xi(1:3,1 ,j,k))*TWOPIIMG)**2.0_pReal)& + + sum(aimag(math_mul33x3_complex(field_fourier(1 ,j,k,1:3,1:3),& + xi(1:3,1 ,j,k))*TWOPIIMG)**2.0_pReal)& + + sum( real(math_mul33x3_complex(field_fourier(res1_red,j,k,1:3,1:3),& + xi(1:3,res1_red,j,k))*TWOPIIMG)**2.0_pReal)& + + sum(aimag(math_mul33x3_complex(field_fourier(res1_red,j,k,1:3,1:3),& + xi(1:3,res1_red,j,k))*TWOPIIMG)**2.0_pReal) + enddo; enddo + + err_div_RMS = sqrt(err_div_RMS)*wgt ! RMS in real space calculated with Parsevals theorem from Fourier space + Utilities_divergenceRMS = err_div_RMS ! criterion to stop iterations + +!-------------------------------------------------------------------------------------------------- +! calculate additional divergence criteria and report + if (debugDivergence) then ! calculate divergence again + err_div_max = 0.0_pReal + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res1_red + temp3_Complex = math_mul33x3_complex(field_fourier(i,j,k,1:3,1:3)*wgt,& ! weighting P_fourier + xi(1:3,i,j,k))*TWOPIIMG + err_div_max = max(err_div_max,sum(abs(temp3_Complex)**2.0_pReal)) + divergence_fourier(i,j,k,1:3) = temp3_Complex ! need divergence NOT squared + enddo; enddo; enddo + + call fftw_execute_dft_c2r(plan_divergence,divergence_fourier,divergence_real) ! already weighted + + err_real_div_RMS = 0.0_pReal + err_post_div_RMS = 0.0_pReal + err_real_div_max = 0.0_pReal + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + err_real_div_RMS = err_real_div_RMS + sum(divergence_real(i,j,k,1:3)**2.0_pReal) ! avg of squared L_2 norm of div(stress) in real space + err_post_div_RMS = err_post_div_RMS + sum(divergence_post(i,j,k,1:3)**2.0_pReal) ! avg of squared L_2 norm of div(stress) in real space + err_real_div_max = max(err_real_div_max,sum(divergence_real(i,j,k,1:3)**2.0_pReal)) ! max of squared L_2 norm of div(stress) in real space + enddo; enddo; enddo + + err_real_div_RMS = sqrt(wgt*err_real_div_RMS) ! RMS in real space + err_post_div_RMS = sqrt(wgt*err_post_div_RMS) ! RMS in real space + err_real_div_max = sqrt( err_real_div_max) ! max in real space + err_div_max = sqrt( err_div_max) ! max in Fourier space + + write(6,'(a,es11.4)') 'error divergence FT RMS = ',err_div_RMS + write(6,'(a,es11.4)') 'error divergence Real RMS = ',err_real_div_RMS + write(6,'(a,es11.4)') 'error divergence post RMS = ',err_post_div_RMS + write(6,'(a,es11.4)') 'error divergence FT max = ',err_div_max + write(6,'(a,es11.4)') 'error divergence Real max = ',err_real_div_max + endif + +end function Utilities_divergenceRMS + + +function Utilities_stressBC(rot_BC,mask_stressVector,C) + + real(pReal), dimension(3,3,3,3) :: Utilities_stressBC + real(pReal), dimension(3,3,3,3), intent(in) :: C + integer(pInt) :: i, j, k, m, n + real(pReal), dimension(3,3), intent(in) :: rot_BC + logical, dimension(9), intent(in) :: mask_stressVector + real(pReal), dimension(3,3,3,3) :: C_lastInc + real(pReal), dimension(9,9) :: temp99_Real + integer(pInt) :: size_reduced = 0_pInt + real(pReal), dimension(:,:), allocatable :: s_reduced, c_reduced ! reduced compliance and stiffness (only for stress BC) + logical :: errmatinv + + size_reduced = count(mask_stressVector) + allocate (c_reduced(size_reduced,size_reduced), source =0.0_pReal) + allocate (s_reduced(size_reduced,size_reduced), source =0.0_pReal) + + C_lastInc = math_rotate_forward3333(C,rot_BC) ! calculate stiffness from former inc + temp99_Real = math_Plain3333to99(C_lastInc) + k = 0_pInt ! build reduced stiffness do n = 1_pInt,9_pInt - if(mask_stressVector1(n)) then + if(mask_stressVector(n)) then k = k + 1_pInt j = 0_pInt do m = 1_pInt,9_pInt - if(mask_stressVector1(m)) then + if(mask_stressVector(m)) then j = j + 1_pInt - temp99_Real(n,m) = s_reduced(k,j) - endif; enddo; endif; enddo - S_lastInc = math_Plain99to3333(temp99_Real) + c_reduced(k,j) = temp99_Real(n,m) + endif; enddo; endif; enddo + call math_invert(size_reduced, c_reduced, s_reduced, i, errmatinv) ! invert reduced stiffness + if(errmatinv) call IO_error(error_ID=400_pInt) + temp99_Real = 0.0_pReal ! build full compliance + k = 0_pInt + do n = 1_pInt,9_pInt + if(mask_stressVector(n)) then + k = k + 1_pInt + j = 0_pInt + do m = 1_pInt,9_pInt + if(mask_stressVector(m)) then + j = j + 1_pInt + temp99_Real(n,m) = s_reduced(k,j) + endif; enddo; endif; enddo + Utilities_stressBC = math_Plain99to3333(temp99_Real) -end function S_lastInc +end function Utilities_stressBC - -!-------------------------------------------------------------------------------------------------- -! calculate reduced compliance - - real(pReal) function BCcorrection(mask_stressVector,P_BC,P_av,F_aim,S_lastInc) - - use numerics, only: err_stress_tolrel, err_stress_tolabs - - logical, dimension(9) :: mask_stressVector - real(pReal) :: err_stress, err_stress_tol - real(pReal), dimension(3,3), parameter :: ones = 1.0_pReal, zeroes = 0.0_pReal - real(pReal), dimension(3,3,3,3) :: S_lastInc - real(pReal), dimension(3,3) :: & - P_BC , & - P_av, & - F_aim, & - mask_stress, & - mask_defgrad - mask_stress = merge(ones,zeroes,reshape(mask_stressVector,[3,3])) - mask_defgrad = merge(zeroes,ones,reshape(mask_stressVector,[3,3])) - -!-------------------------------------------------------------------------------------------------- -! stress BC handling -! calculate stress BC if applied - err_stress = maxval(abs(mask_stress * (P_av - P_BC))) ! maximum deviaton (tensor norm not applicable) - err_stress_tol = min(maxval(abs(P_av)) * err_stress_tolrel,err_stress_tolabs) ! don't use any tensor norm for the relative criterion because the comparison should be coherent - write(6,'(a)') '' - write(6,'(a)') '... correcting deformation gradient to fulfill BCs ...............' - write(6,'(a,f6.2,a,es11.4,a)') 'error stress = ', err_stress/err_stress_tol, & - ' (',err_stress,' Pa)' - F_aim = F_aim - math_mul3333xx33(S_lastInc, ((P_av - P_BC))) ! residual on given stress components - write(6,'(a,1x,es11.4)')'determinant of new deformation = ',math_det33(F_aim) - BCcorrection = err_stress/err_stress_tol - -end function BCcorrection - -subroutine constitutiveResponse(coordinates,F,F_lastInc,temperature,timeinc,& +subroutine Utilities_constitutiveResponse(coordinates,F,F_lastInc,temperature,timeinc,& P,C,P_av,ForwardData,rotation_BC) use debug, only: & debug_reset, & @@ -610,23 +580,24 @@ subroutine constitutiveResponse(coordinates,F,F_lastInc,temperature,timeinc,& write (6,'(a,/,3(3(f12.7,1x)/))',advance='no') 'Piola-Kirchhoff stress / MPa =',& math_transpose33(P_av)/1.e6_pReal C = C * wgt -end subroutine constitutiveResponse + +end subroutine Utilities_constitutiveResponse -subroutine Utilities_destroy +subroutine Utilities_destroy() -implicit none - -if (debugDivergence) then - call fftw_destroy_plan(plan_divergence) -endif - -if (debugFFTW) then - call fftw_destroy_plan(plan_scalarField_forth) - call fftw_destroy_plan(plan_scalarField_back) -endif - -call fftw_destroy_plan(plan_forward) -call fftw_destroy_plan(plan_backward) + implicit none + + if (debugDivergence) then + call fftw_destroy_plan(plan_divergence) + endif + + if (debugFFTW) then + call fftw_destroy_plan(plan_scalarField_forth) + call fftw_destroy_plan(plan_scalarField_back) + endif + + call fftw_destroy_plan(plan_forward) + call fftw_destroy_plan(plan_backward) end subroutine Utilities_destroy