From dec9451b1e50ab40719288097d8900e801fbf056 Mon Sep 17 00:00:00 2001 From: Martin Diehl Date: Wed, 7 Mar 2012 17:37:40 +0000 Subject: [PATCH] first draft of the Augmented Lagrangian based algorithm, still experimental --- code/DAMASK_spectral_AL.f90 | 886 ++++++++++++++++++++++++++++++++++++ 1 file changed, 886 insertions(+) create mode 100644 code/DAMASK_spectral_AL.f90 diff --git a/code/DAMASK_spectral_AL.f90 b/code/DAMASK_spectral_AL.f90 new file mode 100644 index 000000000..208c10c41 --- /dev/null +++ b/code/DAMASK_spectral_AL.f90 @@ -0,0 +1,886 @@ +! Copyright 2011 Max-Planck-Institut für Eisenforschung GmbH +! +! This file is part of DAMASK, +! the Düsseldorf Advanced MAterial Simulation Kit. +! +! DAMASK is free software: you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation, either version 3 of the License, or +! (at your option) any later version. +! +! DAMASK is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with DAMASK. If not, see . +! +!################################################################################################## +!* $Id: DAMASK_spectral.f90 1321 2012-02-15 18:58:38Z MPIE\u.diehl $ +!################################################################################################## +! Material subroutine for BVP solution using spectral method +! +! Run 'DAMASK_spectral.exe --help' to get usage hints +! +! written by P. Eisenlohr, +! F. Roters, +! L. Hantcherli, +! W.A. Counts, +! D.D. Tjahjanto, +! C. Kords, +! M. Diehl, +! R. Lebensohn +! +! MPI fuer Eisenforschung, Duesseldorf +!################################################################################################## +! used modules +!################################################################################################## +program DAMASK_spectral + + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use DAMASK_interface + use prec, only: pInt, pReal, DAMASK_NaN + use IO + use debug, only: debug_spectral, & + debug_levelBasic, & + debug_spectralRestart, & + debug_spectralFFTW + use math + use CPFEM, only: CPFEM_general, CPFEM_initAll + use FEsolving, only: restartWrite, restartInc + use numerics, only: err_div_tol, err_stress_tolrel, rotation_tol, itmax, itmin, & + memory_efficient, update_gamma, DAMASK_NumThreadsInt, & + fftw_planner_flag, fftw_timelimit + use homogenization, only: materialpoint_sizeResults, materialpoint_results + !$ use OMP_LIB ! the openMP function library +!################################################################################################## +! variable declaration +!################################################################################################## + implicit none + +!-------------------------------------------------------------------------------------------------- +! variables to read from load case and geom file + real(pReal), dimension(9) :: temp_valueVector ! stores information temporarily from loadcase file + logical, dimension(9) :: temp_maskVector + integer(pInt), parameter :: maxNchunksLoadcase = (1_pInt + 9_pInt)*3_pInt +& ! deformation, rotation, and stress + (1_pInt + 1_pInt)*5_pInt +& ! time, (log)incs, temp, restartfrequency, and outputfrequency + 1_pInt, & ! dropguessing + maxNchunksGeom = 7_pInt, & ! 4 identifiers, 3 values + myUnit = 234_pInt + integer(pInt), dimension(1_pInt + maxNchunksLoadcase*2_pInt) :: positions ! this is longer than needed for geometry parsing + integer(pInt) :: headerLength,& + N_l = 0_pInt,& + N_t = 0_pInt,& + N_n = 0_pInt,& + N_Fdot = 0_pInt + character(len=1024) :: path, line, keyword + logical :: gotResolution = .false.,& + gotDimension = .false.,& + gotHomogenization = .false. + +!-------------------------------------------------------------------------------------------------- +! variable storing information from load case file + type bc_type + real(pReal), dimension (3,3) :: deformation = 0.0_pReal, & ! applied velocity gradient or time derivative of deformation gradient + stress = 0.0_pReal, & ! stress BC (if applicable) + rotation = math_I3 ! rotation of BC (if applicable) + real(pReal) :: time = 0.0_pReal, & ! length of increment + temperature = 300.0_pReal ! isothermal starting conditions + integer(pInt) :: incs = 0_pInt, & ! number of increments + outputfrequency = 1_pInt, & ! frequency of result writes + restartfrequency = 0_pInt, & ! frequency of restart writes + logscale = 0_pInt ! linear/logaritmic time inc flag + logical :: followFormerTrajectory = .true., & ! follow trajectory of former loadcase + velGradApplied = .false. ! decide wether velocity gradient or fdot is given + logical, dimension(3,3) :: maskDeformation = .false., & ! mask of deformation boundary conditions + maskStress = .false. ! mask of stress boundary conditions + logical, dimension(9) :: maskStressVector = .false. ! linear mask of boundary conditions + end type + + type(bc_type), allocatable, dimension(:) :: bc + +!-------------------------------------------------------------------------------------------------- +! variables storing information from geom file + real(pReal) :: wgt + real(pReal), dimension(3) :: geomdim = 0.0_pReal ! physical dimension of volume element per direction + integer(pInt) :: Npoints,& ! number of Fourier points + homog ! homogenization scheme used + integer(pInt), dimension(3) :: res = 1_pInt ! resolution (number of Fourier points) in each direction + integer(pInt) :: res1_red ! to store res(1)/2 +1 + +!-------------------------------------------------------------------------------------------------- +! stress, stiffness and compliance average etc. + real(pReal), dimension(3,3) :: P_av, P, F_aim = math_I3, F_aim_lastInc = math_I3,& + mask_stress, mask_defgrad, deltaF, F_star_av, & + F_aim_lab ! quantities rotated to other coordinate system + real(pReal), dimension(3,3,3,3) :: dPdF, C_inc0, C=0.0_pReal, S_lastInc, C_lastInc ! stiffness and compliance + real(pReal), dimension(6) :: sigma ! cauchy stress + real(pReal), dimension(6,6) :: dsde ! small strain stiffness + real(pReal), dimension(9,9) :: s_prev99, c_prev99 ! compliance and stiffness in matrix notation + real(pReal), dimension(:,:), allocatable :: s_reduced, c_reduced ! reduced compliance and stiffness (only for stress BC) + integer(pInt) :: size_reduced = 0_pInt ! number of stress BCs + +!-------------------------------------------------------------------------------------------------- +! pointwise data + type(C_PTR) :: tensorField ! fields in real an fourier space + real(pReal), dimension(:,:,:,:,:), pointer :: lambda_real, F_real ! fields in real space (pointer) + complex(pReal), dimension(:,:,:,:,:), pointer :: lambda_fourier, F_fourier ! fields in fourier space (pointer) + real(pReal), dimension(:,:,:,:,:), allocatable :: F_lastInc, F_star, lambda + real(pReal), dimension(:,:,:,:), allocatable :: coordinates + real(pReal), dimension(:,:,:), allocatable :: temperature + +!-------------------------------------------------------------------------------------------------- +! variables storing information for spectral method and FFTW + type(C_PTR) :: plan_correction, plan_lambda ! plans for fftw + real(pReal), dimension(3,3) :: xiDyad ! product of wave vectors + real(pReal), dimension(:,:,:,:,:,:,:), allocatable :: gamma_hat ! gamma operator (field) for spectral method + real(pReal), dimension(:,:,:,:), allocatable :: xi ! wave vector field for divergence and for gamma operator + integer(pInt), dimension(3) :: k_s + +!-------------------------------------------------------------------------------------------------- +! loop variables, convergence etc. + real(pReal) :: time = 0.0_pReal, time0 = 0.0_pReal, timeinc = 1.0_pReal, timeinc_old = 0.0_pReal ! elapsed time, begin of interval, time interval + real(pReal) :: guessmode, err_stress, err_stress_tol, err_f, err_p, err_crit + real(pReal), dimension(3,3), parameter :: ones = 1.0_pReal, zeroes = 0.0_pReal + complex(pReal), dimension(3,3) :: temp33_Complex + real(pReal), dimension(3,3) :: temp33_Real + integer(pInt) :: i, j, k, l, u, v, w, errorID = 0_pInt, ierr + integer(pInt) :: N_Loadcases, loadcase, inc, iter, ielem, CPFEM_mode, & + totalIncsCounter = 0_pInt,notConvergedCounter = 0_pInt, convergedCounter = 0_pInt + logical :: errmatinv + character(len=6) :: loadcase_string + +!-------------------------------------------------------------------------------------------------- +!variables controlling debugging + logical :: debugGeneral, debugDivergence, debugRestart, debugFFTW + +!################################################################################################## +! reading of information from load case file and geometry file +!################################################################################################## + !$ call omp_set_num_threads(DAMASK_NumThreadsInt) ! set number of threads for parallel execution set by DAMASK_NUM_THREADS + open (6, encoding='UTF-8') + call DAMASK_interface_init + + print '(a)', '' + print '(a)', ' <<<+- DAMASK_spectral init -+>>>' + print '(a)', ' $Id: DAMASK_spectral.f90 1321 2012-02-15 18:58:38Z MPIE\u.diehl $' +#include "compilation_info.f90" + print '(a,a)', ' Working Directory: ',trim(getSolverWorkingDirectoryName()) + print '(a,a)', ' Solver Job Name: ',trim(getSolverJobName()) + print '(a)', '' +!-------------------------------------------------------------------------------------------------- +! reading the load case file and allocate data structure containing load cases + path = getLoadcaseName() + call IO_open_file(myUnit,path) + rewind(myUnit) + do + read(myUnit,'(a1024)',END = 100) line + if (IO_isBlank(line)) cycle ! skip empty lines + positions = IO_stringPos(line,maxNchunksLoadcase) + do i = 1_pInt, maxNchunksLoadcase, 1_pInt ! reading compulsory parameters for loadcase + select case (IO_lc(IO_stringValue(line,positions,i))) + case('l','velocitygrad','velgrad','velocitygradient') + N_l = N_l + 1_pInt + case('fdot','dotf') + N_Fdot = N_Fdot + 1_pInt + case('t','time','delta') + N_t = N_t + 1_pInt + case('n','incs','increments','steps','logincs','logsteps') + N_n = N_n + 1_pInt + end select + enddo ! count all identifiers to allocate memory and do sanity check + enddo + +100 N_Loadcases = N_n + if ((N_l + N_Fdot /= N_n) .or. (N_n /= N_t)) & ! sanity check + call IO_error(error_ID=837_pInt,ext_msg = trim(path)) ! error message for incomplete loadcase + !if (N_Loadcases>9000_pInt) stop !discuss with Philip, stop code trouble. suggesting warning + + allocate (bc(N_Loadcases)) + +!-------------------------------------------------------------------------------------------------- +! reading the load case and assign values to the allocated data structure + rewind(myUnit) + loadcase = 0_pInt + do + read(myUnit,'(a1024)',END = 101) line + if (IO_isBlank(line)) cycle ! skip empty lines + loadcase = loadcase + 1_pInt + positions = IO_stringPos(line,maxNchunksLoadcase) + do j = 1_pInt,maxNchunksLoadcase + select case (IO_lc(IO_stringValue(line,positions,j))) + case('fdot','dotf','l','velocitygrad','velgrad','velocitygradient') ! assign values for the deformation BC matrix + bc(loadcase)%velGradApplied = & + (IO_lc(IO_stringValue(line,positions,j)) == 'l'.or. & ! in case of given L, set flag to true + IO_lc(IO_stringValue(line,positions,j)) == 'velocitygrad'.or.& + IO_lc(IO_stringValue(line,positions,j)) == 'velgrad'.or.& + IO_lc(IO_stringValue(line,positions,j)) == 'velocitygradient') + temp_valueVector = 0.0_pReal + temp_maskVector = .false. + forall (k = 1_pInt:9_pInt) temp_maskVector(k) = IO_stringValue(line,positions,j+k) /= '*' + do k = 1_pInt,9_pInt + if (temp_maskVector(k)) temp_valueVector(k) = IO_floatValue(line,positions,j+k) + enddo + bc(loadcase)%maskDeformation = transpose(reshape(temp_maskVector,[ 3,3])) + bc(loadcase)%deformation = math_plain9to33(temp_valueVector) + case('p','pk1','piolakirchhoff','stress') + temp_valueVector = 0.0_pReal + forall (k = 1_pInt:9_pInt) bc(loadcase)%maskStressVector(k) =& + IO_stringValue(line,positions,j+k) /= '*' + do k = 1_pInt,9_pInt + if (bc(loadcase)%maskStressVector(k)) temp_valueVector(k) =& + IO_floatValue(line,positions,j+k) ! assign values for the bc(loadcase)%stress matrix + enddo + bc(loadcase)%maskStress = transpose(reshape(bc(loadcase)%maskStressVector,[ 3,3])) + bc(loadcase)%stress = math_plain9to33(temp_valueVector) + case('t','time','delta') ! increment time + bc(loadcase)%time = IO_floatValue(line,positions,j+1_pInt) + case('temp','temperature') ! starting temperature + bc(loadcase)%temperature = IO_floatValue(line,positions,j+1_pInt) + case('n','incs','increments','steps') ! number of increments + bc(loadcase)%incs = IO_intValue(line,positions,j+1_pInt) + case('logincs','logincrements','logsteps') ! number of increments (switch to log time scaling) + bc(loadcase)%incs = IO_intValue(line,positions,j+1_pInt) + bc(loadcase)%logscale = 1_pInt + case('f','freq','frequency','outputfreq') ! frequency of result writings + bc(loadcase)%outputfrequency = IO_intValue(line,positions,j+1_pInt) + case('r','restart','restartwrite') ! frequency of writing restart information + bc(loadcase)%restartfrequency = max(0_pInt,IO_intValue(line,positions,j+1_pInt)) + case('guessreset','dropguessing') + bc(loadcase)%followFormerTrajectory = .false. ! do not continue to predict deformation along former trajectory + case('euler') ! rotation of loadcase given in euler angles + u = 0_pInt ! assuming values given in radians + v = 1_pInt ! assuming keyword indicating degree/radians + select case (IO_lc(IO_stringValue(line,positions,j+1_pInt))) + case('deg','degree') + u = 1_pInt ! for conversion from degree to radian + case('rad','radian') + case default + v = 0_pInt ! immediately reading in angles, assuming radians + end select + forall(k = 1_pInt:3_pInt) temp33_Real(k,1) = & + IO_floatValue(line,positions,j+v+k) * real(u,pReal) * inRad + bc(loadcase)%rotation = math_EulerToR(temp33_Real(:,1)) + case('rotation','rot') ! assign values for the rotation of loadcase matrix + temp_valueVector = 0.0_pReal + forall (k = 1_pInt:9_pInt) temp_valueVector(k) = IO_floatValue(line,positions,j+k) + bc(loadcase)%rotation = math_plain9to33(temp_valueVector) + end select + enddo; enddo +101 close(myUnit) + +!-------------------------------------------------------------------------------------------------- ToDo: if temperature at CPFEM is treated properly, move this up immediately after interface init +! initialization of all related DAMASK modules (e.g. mesh.f90 reads in geometry) + call CPFEM_initAll(bc(1)%temperature,1_pInt,1_pInt) + if (update_gamma .and. .not. memory_efficient) call IO_error(error_ID = 847_pInt) + +!-------------------------------------------------------------------------------------------------- +! read header of geom file to get size information. complete geom file is intepretated by mesh.f90 + path = getModelName() + call IO_open_file(myUnit,trim(path)//InputFileExtension) + rewind(myUnit) + read(myUnit,'(a1024)') line + positions = IO_stringPos(line,2_pInt) + keyword = IO_lc(IO_StringValue(line,positions,2_pInt)) + if (keyword(1:4) == 'head') then + headerLength = IO_intValue(line,positions,1_pInt) + 1_pInt + else + call IO_error(error_ID=842_pInt) + endif + + rewind(myUnit) + do i = 1_pInt, headerLength + read(myUnit,'(a1024)') line + positions = IO_stringPos(line,maxNchunksGeom) + select case ( IO_lc(IO_StringValue(line,positions,1)) ) + case ('dimension') + gotDimension = .true. + do j = 2_pInt,6_pInt,2_pInt + select case (IO_lc(IO_stringValue(line,positions,j))) + case('x') + geomdim(1) = IO_floatValue(line,positions,j+1_pInt) + case('y') + geomdim(2) = IO_floatValue(line,positions,j+1_pInt) + case('z') + geomdim(3) = IO_floatValue(line,positions,j+1_pInt) + end select + enddo + case ('homogenization') + gotHomogenization = .true. + homog = IO_intValue(line,positions,2_pInt) + case ('resolution') + gotResolution = .true. + do j = 2_pInt,6_pInt,2_pInt + select case (IO_lc(IO_stringValue(line,positions,j))) + case('a') + res(1) = IO_intValue(line,positions,j+1_pInt) + case('b') + res(2) = IO_intValue(line,positions,j+1_pInt) + case('c') + res(3) = IO_intValue(line,positions,j+1_pInt) + end select + enddo + end select + enddo + close(myUnit) + +!-------------------------------------------------------------------------------------------------- +! sanity checks of geometry parameters + if (.not.(gotDimension .and. gotHomogenization .and. gotResolution))& + call IO_error(error_ID = 845_pInt) + if (any(geomdim<=0.0_pReal)) call IO_error(error_ID = 802_pInt) + if(mod(res(1),2_pInt)/=0_pInt .or.& + mod(res(2),2_pInt)/=0_pInt .or.& + (mod(res(3),2_pInt)/=0_pInt .and. res(3)/= 1_pInt)) call IO_error(error_ID = 803_pInt) + +!-------------------------------------------------------------------------------------------------- +! variables derived from resolution + res1_red = res(1)/2_pInt + 1_pInt ! size of complex array in first dimension (c2r, r2c) + Npoints = res(1)*res(2)*res(3) + wgt = 1.0_pReal/real(Npoints, pReal) + +!-------------------------------------------------------------------------------------------------- +! output of geometry + print '(a)', '' + print '(a)', '#############################################################' + print '(a)', 'DAMASK spectral:' + print '(a)', 'The spectral method boundary value problem solver for' + print '(a)', 'the Duesseldorf Advanced Material Simulation Kit' + print '(a)', '#############################################################' + print '(a,a)', 'geometry file: ',trim(path)//'.geom' + print '(a)', '=============================================================' + print '(a,3(i12 ))','resolution a b c:', res + print '(a,3(f12.5))','dimension x y z:', geomdim + print '(a,i5)','homogenization: ',homog + print '(a)', '#############################################################' + print '(a,a)', 'loadcase file: ',trim(getLoadcaseName()) + +!-------------------------------------------------------------------------------------------------- +! consistency checks and output of load case + bc(1)%followFormerTrajectory = .false. ! cannot guess along trajectory for first inc of first loadcase + + do loadcase = 1_pInt, N_Loadcases + write (loadcase_string, '(i6)' ) loadcase + + print '(a)', '=============================================================' + print '(a,i6)', 'loadcase: ', loadcase + + if (.not. bc(loadcase)%followFormerTrajectory) print '(a)', 'drop guessing along trajectory' + if (bc(loadcase)%velGradApplied) then + do j = 1_pInt, 3_pInt + if (any(bc(loadcase)%maskDeformation(j,1:3) .eqv. .true.) .and. & + any(bc(loadcase)%maskDeformation(j,1:3) .eqv. .false.)) errorID = 832_pInt ! each row should be either fully or not at all defined + enddo + print '(a)','velocity gradient:' + else + print '(a)','deformation gradient rate:' + endif + write (*,'(3(3(f12.7,1x)/))',advance='no') merge(math_transpose33(bc(loadcase)%deformation),& + reshape(spread(DAMASK_NaN,1,9),[ 3,3]),transpose(bc(loadcase)%maskDeformation)) + write (*,'(a,/,3(3(f12.7,1x)/))',advance='no') 'stress / GPa:',& + 1e-9_pReal*merge(math_transpose33(bc(loadcase)%stress),& + reshape(spread(DAMASK_NaN,1,9),[ 3,3]),transpose(bc(loadcase)%maskStress)) + if (any(bc(loadcase)%rotation /= math_I3)) & + write (*,'(a,/,3(3(f12.7,1x)/))',advance='no') ' rotation of loadframe:',& + math_transpose33(bc(loadcase)%rotation) + print '(a,f12.6)','temperature:',bc(loadcase)%temperature + print '(a,f12.6)','time: ',bc(loadcase)%time + print '(a,i5)' ,'increments: ',bc(loadcase)%incs + print '(a,i5)','output frequency: ',bc(loadcase)%outputfrequency + print '(a,i5)','restart frequency: ',bc(loadcase)%restartfrequency + if (any(bc(loadcase)%maskStress .eqv. bc(loadcase)%maskDeformation)) errorID = 831_pInt ! exclusive or masking only + if (any(bc(loadcase)%maskStress .and. transpose(bc(loadcase)%maskStress) .and. & + reshape([ .false.,.true.,.true.,.true.,.false.,.true.,.true.,.true.,.false.],[ 3,3]))) & + errorID = 838_pInt ! no rotation is allowed by stress BC + if (any(abs(math_mul33x33(bc(loadcase)%rotation,math_transpose33(bc(loadcase)%rotation))& + -math_I3) > reshape(spread(rotation_tol,1,9),[ 3,3]))& + .or. abs(math_det33(bc(loadcase)%rotation)) > 1.0_pReal + rotation_tol)& + errorID = 846_pInt ! given rotation matrix contains strain + if (bc(loadcase)%time < 0.0_pReal) errorID = 834_pInt ! negative time increment + if (bc(loadcase)%incs < 1_pInt) errorID = 835_pInt ! non-positive incs count + if (bc(loadcase)%outputfrequency < 1_pInt) errorID = 836_pInt ! non-positive result frequency + if (errorID > 0_pInt) call IO_error(error_ID = errorID, ext_msg = loadcase_string) + enddo + +!-------------------------------------------------------------------------------------------------- +! debugging parameters + debugRestart = iand(debug_spectral,debug_spectralRestart) > 0_pInt + debugFFTW = iand(debug_spectral,debug_spectralFFTW) > 0_pInt + debugGeneral = .true. + +!################################################################################################## +! initialization +!################################################################################################## + +!-------------------------------------------------------------------------------------------------- +! allocate more memory + allocate (F_star ( 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 (lambda ( res(1), res(2),res(3),3,3), source = 0.0_pReal) + allocate (xi (3,res1_red,res(2),res(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 = bc(1)%temperature) ! start out isothermally + tensorField = fftw_alloc_complex(int(res1_red*res(2)*res(3)*9_pInt,C_SIZE_T)) ! allocate continous data using a C function, C_SIZE_T is of type integer(8) + call c_f_pointer(tensorField, lambda_real, [ res(1)+2_pInt,res(2),res(3),3,3]) ! place a pointer for the real representation + call c_f_pointer(tensorField, F_real, [ res(1)+2_pInt,res(2),res(3),3,3]) ! place a pointer for the real representation + call c_f_pointer(tensorField, lambda_fourier, [ res1_red, res(2),res(3),3,3]) ! place a pointer for the complex representation + call c_f_pointer(tensorField, F_fourier, [ res1_red, res(2),res(3),3,3]) ! place a pointer for the complex representation + +!-------------------------------------------------------------------------------------------------- +! general initialization of fftw (see manual on fftw.org for more details) + if (pReal /= C_DOUBLE .or. pInt /= C_INT) call IO_error(error_ID=808_pInt) ! check for correct precision in C +#ifdef _OPENMP + if(DAMASK_NumThreadsInt > 0_pInt) then + ierr = fftw_init_threads() + if (ierr == 0_pInt) call IO_error(error_ID = 809_pInt) + call fftw_plan_with_nthreads(DAMASK_NumThreadsInt) + endif +#endif + call fftw_set_timelimit(fftw_timelimit) ! set timelimit for plan creation + +!-------------------------------------------------------------------------------------------------- +! creating plans + plan_lambda = fftw_plan_many_dft_r2c(3,[ res(3),res(2) ,res(1)],9,& ! dimensions , length in each dimension in reversed order + lambda_real,[ res(3),res(2) ,res(1)+2_pInt],& ! input data , physical length in each dimension in reversed order + 1, res(3)*res(2)*(res(1)+2_pInt),& ! striding , product of physical lenght in the 3 dimensions + lambda_fourier,[ res(3),res(2) ,res1_red],& + 1, res(3)*res(2)* res1_red,fftw_planner_flag) + + plan_correction = fftw_plan_many_dft_c2r(3,[ res(3),res(2) ,res(1)],9,& + F_fourier,[ res(3),res(2) ,res1_red],& + 1, res(3)*res(2)* res1_red,& + F_real,[ res(3),res(2) ,res(1)+2_pInt],& + 1, res(3)*res(2)*(res(1)+2_pInt),fftw_planner_flag) + if (debugGeneral) print '(a)' , 'FFTW initialized' + +!-------------------------------------------------------------------------------------------------- +! calculation of discrete angular frequencies, ordered as in FFTW (wrap around) and remove the given highest frequencies + do k = 1_pInt, res(3) + k_s(3) = k - 1_pInt + if(k > res(3)/2_pInt + 1_pInt) k_s(3) = k_s(3) - res(3) + do j = 1_pInt, res(2) + k_s(2) = j - 1_pInt + if(j > res(2)/2_pInt + 1_pInt) k_s(2) = k_s(2) - res(2) + do i = 1_pInt, res1_red + k_s(1) = i - 1_pInt + xi(1:3,i,j,k) = real(k_s, pReal)/geomdim + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! calculate the gamma operator + 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, u = 1_pInt:3_pInt) & + xiDyad(l,u) = xi(l, i,j,k)*xi(u, i,j,k) + forall(l = 1_pInt:3_pInt, u = 1_pInt:3_pInt) & + temp33_Real(l,u) = sum(C_inc0(l,1:3,u,1:3)*xiDyad) + temp33_Real = math_inv33(temp33_Real) + forall(l=1_pInt:3_pInt, u=1_pInt:3_pInt, v=1_pInt:3_pInt, w=1_pInt:3_pInt)& + gamma_hat(i,j,k, l,u,v,w) = temp33_Real(l,v)*xiDyad(u,w) + 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 + +!-------------------------------------------------------------------------------------------------- +! init fields to no deformation + ielem = 0_pInt + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + ielem = ielem + 1_pInt + F_real(i,j,k,1:3,1:3) = math_I3; F_lastInc(i,j,k,1:3,1:3) = math_I3 + coordinates(i,j,k,1:3) = geomdim/real(res * [i,j,k], pReal) - geomdim/real(2_pInt*res,pReal) + call CPFEM_general(3_pInt,coordinates(i,j,k,1:3),math_I3,math_I3,temperature(i,j,k),& + 0.0_pReal,ielem,1_pInt,sigma,dsde,temp33_Real ,dPdF) + enddo; enddo; enddo + + ielem = 0_pInt + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + ielem = ielem + 1_pInt + call CPFEM_general(2_pInt,coordinates(i,j,k,1:3),math_I3,math_I3,temperature(i,j,k),& + 0.0_pReal,ielem,1_pInt,sigma,dsde,temp33_Real ,dPdF) + C = C + dPdF + enddo; enddo; enddo + C_inc0 = C * wgt ! linear reference material stiffness + P_av = 0.0_pReal + + !-------------------------------------------------------------------------------------------------- +! possible restore deformation gradient from saved state + if (restartInc > 1_pInt) then ! using old values from file + if (debugRestart) print '(a,i6,a)' , 'Reading values of increment ',& + restartInc - 1_pInt,' from file' + call IO_read_jobBinaryFile(777,'convergedSpectralDefgrad',& + trim(getSolverJobName()),size(F_star)) + read (777,rec=1) F_star + close (777) + F_real(1:res(1),1:res(2),1:res(3),1:3,1:3) = F_star + F_lastInc = F_star + F_aim = 0.0_pReal + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + F_aim = F_aim + F_real(i,j,k,1:3,1:3) ! calculating old average deformation + enddo; enddo; enddo + F_aim = F_aim * wgt + F_aim_lastInc = F_aim + endif + +!-------------------------------------------------------------------------------------------------- +! write header of output file + open(538,file=trim(getSolverWorkingDirectoryName())//trim(getSolverJobName())& + //'.spectralOut',form='UNFORMATTED',status='REPLACE') + write(538) 'load', trim(getLoadcaseName()) + write(538) 'workingdir', trim(getSolverWorkingDirectoryName()) + write(538) 'geometry', trim(getSolverJobName())//InputFileExtension + write(538) 'resolution', res + write(538) 'dimension', geomdim + write(538) 'materialpoint_sizeResults', materialpoint_sizeResults + write(538) 'loadcases', N_Loadcases + write(538) 'frequencies', bc(1:N_Loadcases)%outputfrequency ! one entry per loadcase + write(538) 'times', bc(1:N_Loadcases)%time ! one entry per loadcase + write(538) 'logscales', bc(1:N_Loadcases)%logscale + write(538) 'increments', bc(1:N_Loadcases)%incs ! one entry per loadcase + write(538) 'startingIncrement', restartInc - 1_pInt ! start with writing out the previous inc + write(538) 'eoh' ! end of header + write(538) materialpoint_results(1_pInt:materialpoint_sizeResults,1,1_pInt:Npoints) ! initial (non-deformed or read-in) results + if (debugGeneral) print '(a)' , 'Header of result file written out' + +!################################################################################################## +! Loop over loadcases defined in the loadcase file +!################################################################################################## + do loadcase = 1_pInt, N_Loadcases + time0 = time ! loadcase start time + if (bc(loadcase)%followFormerTrajectory .and. & + (restartInc < totalIncsCounter .or. & + restartInc > totalIncsCounter+bc(loadcase)%incs) ) then ! continue to guess along former trajectory where applicable + guessmode = 1.0_pReal + else + guessmode = 0.0_pReal ! change of load case, homogeneous guess for the first inc + endif + +!-------------------------------------------------------------------------------------------------- +! arrays for mixed boundary conditions + mask_defgrad = merge(ones,zeroes,bc(loadcase)%maskDeformation) + mask_stress = merge(ones,zeroes,bc(loadcase)%maskStress) + size_reduced = int(count(bc(loadcase)%maskStressVector), pInt) + allocate (c_reduced(size_reduced,size_reduced), source =0.0_pReal) + allocate (s_reduced(size_reduced,size_reduced), source =0.0_pReal) + +!################################################################################################## +! loop oper incs defined in input file for current loadcase +!################################################################################################## + do inc = 1_pInt, bc(loadcase)%incs + totalIncsCounter = totalIncsCounter + 1_pInt + if(totalIncsCounter >= restartInc) then ! do calculations (otherwise just forwarding) +!-------------------------------------------------------------------------------------------------- +! forwarding time + timeinc_old = timeinc + if (bc(loadcase)%logscale == 0_pInt) then ! linear scale + timeinc = bc(loadcase)%time/bc(loadcase)%incs ! only valid for given linear time scale. will be overwritten later in case loglinear scale is used + else + if (loadcase == 1_pInt) then ! 1st loadcase of logarithmic scale + if (inc == 1_pInt) then ! 1st inc of 1st loadcase of logarithmic scale + timeinc = bc(1)%time*(2.0_pReal**real( 1_pInt-bc(1)%incs ,pReal)) ! assume 1st inc is equal to 2nd + else ! not-1st inc of 1st loadcase of logarithmic scale + timeinc = bc(1)%time*(2.0_pReal**real(inc-1_pInt-bc(1)%incs ,pReal)) + endif + else ! not-1st loadcase of logarithmic scale + timeinc = time0 *( (1.0_pReal + bc(loadcase)%time/time0 )**(real( inc,pReal)/& + real(bc(loadcase)%incs ,pReal))& + -(1.0_pReal + bc(loadcase)%time/time0 )**(real( (inc-1_pInt),pReal)/& + real(bc(loadcase)%incs ,pReal)) ) + endif + endif + time = time + timeinc + + if (bc(loadcase)%velGradApplied) then ! calculate deltaF from given L and current F + deltaF = timeinc * mask_defgrad * math_mul33x33(bc(loadcase)%deformation, F_aim) + else ! deltaF = fDot *timeinc where applicable + deltaF = timeinc * mask_defgrad * bc(loadcase)%deformation + endif + +!-------------------------------------------------------------------------------------------------- +! coordinates at beginning of inc + call deformed_fft(res,geomdim,math_rotate_backward33(F_aim,bc(loadcase)%rotation),& ! calculate current coordinates + 1.0_pReal,F_real(1:res(1),1:res(2),1:res(3),1:3,1:3),coordinates) + +!-------------------------------------------------------------------------------------------------- +! winding forward of deformation aim in loadcase system + temp33_Real = F_aim + F_aim = F_aim & + + guessmode * mask_stress * (F_aim - F_aim_lastInc)*timeinc/timeinc_old & + + deltaF + F_aim_lastInc = temp33_Real + F_star_av = F_aim +!-------------------------------------------------------------------------------------------------- +! update local deformation gradient + deltaF = math_rotate_backward33(deltaF,bc(loadcase)%rotation) + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + temp33_Real = F_real(i,j,k,1:3,1:3) + F_real(i,j,k,1:3,1:3) = F_real(i,j,k,1:3,1:3) & ! decide if guessing along former trajectory or apply homogeneous addon + + guessmode * (F_real(i,j,k,1:3,1:3) - F_lastInc(i,j,k,1:3,1:3))& ! guessing... + *timeinc/timeinc_old & + + (1.0_pReal-guessmode) * deltaF ! if not guessing, use prescribed average deformation where applicable + F_lastInc(i,j,k,1:3,1:3) = temp33_Real + enddo; enddo; enddo + + +!-------------------------------------------------------------------------------------------------- +!Initialize pointwise data for AL scheme: ToDo: good choice? + F_star(1:res(1),1:res(2),1:res(3),1:3,1:3) = F_real(1:res(1),1:res(2),1:res(3),1:3,1:3) + lambda = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! calculate reduced compliance + + if(size_reduced > 0_pInt) then ! calculate compliance in case stress BC is applied + C_lastInc = math_rotate_forward3333(C*wgt,bc(loadcase)%rotation) ! calculate stiffness from former inc + c_prev99 = math_Plain3333to99(C_lastInc) + k = 0_pInt ! build reduced stiffness + do v = 1_pInt,9_pInt + if(bc(loadcase)%maskStressVector(v)) then + k = k + 1_pInt + j = 0_pInt + do u = 1_pInt,9_pInt + if(bc(loadcase)%maskStressVector(u)) then + j = j + 1_pInt + c_reduced(k,j) = c_prev99(v,u) + 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) + s_prev99 = 0.0_pReal ! build full compliance + k = 0_pInt + do v = 1_pInt,9_pInt + if(bc(loadcase)%maskStressVector(v)) then + k = k + 1_pInt + j = 0_pInt + do u = 1_pInt,9_pInt + if(bc(loadcase)%maskStressVector(u)) then + j = j + 1_pInt + s_prev99(v,u) = s_reduced(k,j) + endif; enddo; endif; enddo + S_lastInc = (math_Plain99to3333(s_prev99)) + endif + +!-------------------------------------------------------------------------------------------------- +! report begin of new increment + print '(a)', '##################################################################' + print '(A,I5.5,A,es12.5)', 'Increment ', totalIncsCounter, ' Time ',time + + guessmode = 1.0_pReal ! keep guessing along former trajectory during same loadcase + CPFEM_mode = 1_pInt ! winding forward + iter = 0_pInt + err_crit = 2.0_pReal * err_div_tol ! go into loop + +!################################################################################################## +! convergence loop (looping over iterations) +!################################################################################################## + do while((iter < itmax .and. (err_crit > err_div_tol .or. err_stress > err_stress_tol))& + .or. iter < itmin) + iter = iter + 1_pInt + +!-------------------------------------------------------------------------------------------------- +! report begin of new iteration + print '(a)', '' + print '(a)', '==================================================================' + print '(5(a,i6.6))', 'Loadcase ',loadcase,' Increment ',inc,'/',bc(loadcase)%incs,& + ' @ Iteration ',iter,'/',itmax + +!-------------------------------------------------------------------------------------------------- +! stress BC handling + if(size_reduced > 0_pInt) then ! calculate stress BC if applied + err_stress = maxval(abs(mask_stress * (P_av - bc(loadcase)%stress))) ! maximum deviaton (tensor norm not applicable) + write (*,'(a,/,3(3(es14.7,1x)/))',advance='no') 'stress deviation =',& + math_transpose33(mask_stress * (P_av - bc(loadcase)%stress))/1.0e6_pReal + F_aim = F_aim + math_mul3333xx33(S_lastInc,bc(loadcase)%stress- P_av) + err_stress_tol = maxval(abs(P_av)) * err_stress_tolrel ! don't use any tensor norm because the comparison should be coherent + else + err_stress_tol = + huge(1.0_pReal) + endif + F_aim_lab = math_rotate_backward33(F_aim,bc(loadcase)%rotation) + write (*,'(a,/,3(3(es14.7,1x)/))',advance='no') 'F =',& + math_transpose33(F_aim) + temp33_real = 0.0_pReal + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + temp33_real = temp33_real + F_star(i,j,k,1:3,1:3) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! doing Fourier transform + print '(a)', '... spectral method ...............................................' + lambda_real(1:res(1),1:res(2),1:res(3),1:3,1:3) = lambda(1:res(1),1:res(2),1:res(3),1:3,1:3) + call fftw_execute_dft_r2c(plan_lambda,lambda_real,lambda_fourier) + lambda_fourier( res1_red,1:res(2) , 1:res(3) ,1:3,1:3)& + = cmplx(0.0_pReal,0.0_pReal,pReal) + lambda_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) & + lambda_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) + +!-------------------------------------------------------------------------------------------------- +! using gamma operator to update F + 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, u = 1_pInt:3_pInt) & + xiDyad(l,u) = xi(l, i,j,k)*xi(u, i,j,k) + forall(l = 1_pInt:3_pInt, u = 1_pInt:3_pInt) & + temp33_Real(l,u) = sum(C_inc0(l,1:3,u,1:3)*xiDyad) + temp33_Real = math_inv33(temp33_Real) + forall(l=1_pInt:3_pInt, u=1_pInt:3_pInt, v=1_pInt:3_pInt, w=1_pInt:3_pInt)& + gamma_hat(1,1,1, l,u,v,w) = temp33_Real(l,v)*xiDyad(u,w) + forall(l = 1_pInt:3_pInt, u = 1_pInt:3_pInt) & + temp33_Complex(l,u) = sum(gamma_hat(1,1,1, l,u, 1:3,1:3) *& + lambda_fourier(i,j,k,1:3,1:3)) + F_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( u = 1_pInt:3_pInt, v = 1_pInt:3_pInt) & + temp33_Complex(u,v) = sum(gamma_hat(i,j,k, u,v, 1:3,1:3) *& + lambda_fourier(i,j,k,1:3,1:3)) + F_fourier(i,j,k, 1:3,1:3) = - temp33_Complex + enddo; enddo; enddo + endif + F_fourier(1,1,1,1:3,1:3) = cmplx((F_aim_lab - F_star_av)*real(Npoints,pReal),0.0_pReal,pReal) +!-------------------------------------------------------------------------------------------------- +! doing inverse Fourier transform + call fftw_execute_dft_c2r(plan_correction,F_fourier,F_real) ! back transform of fluct deformation gradient + F_real(1:res(1),1:res(2),1:res(3),1:3,1:3) = F_real(1:res(1),1:res(2),1:res(3),1:3,1:3) * wgt + & + F_star(1:res(1),1:res(2),1:res(3),1:3,1:3) + +!-------------------------------------------------------------------------------------------------- +! + print '(a)', '... update stress field P(F*) .....................................' + ielem = 0_pInt + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + ielem = ielem + 1_pInt + call CPFEM_general(3_pInt,& ! collect cycle + coordinates(i,j,k,1:3), F_lastInc(i,j,k,1:3,1:3),& + F_star(i,j,k,1:3,1:3),temperature(i,j,k),timeinc,ielem,1_pInt,& + sigma,dsde, P, dPdF) + enddo; enddo; enddo + + ielem = 0_pInt + err_f = 0.0_pReal + F_star_av = 0.0_pReal + P_av =0.0_pReal + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + ielem = ielem + 1_pInt + call CPFEM_general(CPFEM_mode,& + coordinates(i,j,k,1:3),F_lastInc(i,j,k,1:3,1:3), & + F_star(i,j,k,1:3,1:3),temperature(i,j,k),timeinc,ielem,1_pInt,& + sigma,dsde, P,dPdF) + CPFEM_mode = 2_pInt ! winding forward + P_av = P_av + P + temp33_Real = lambda(i,j,k,1:3,1:3) - P & + + math_mul3333xx33(C_inc0,F_real(i,j,k,1:3,1:3)- F_star(i,j,k,1:3,1:3)) + F_star(i,j,k,1:3,1:3) = F_star(i,j,k,1:3,1:3) + & + math_mul3333xx33(math_invSym3333(C_inc0 + dPdF), temp33_Real) + lambda(i,j,k,1:3,1:3) = lambda(i,j,k,1:3,1:3) + math_mul3333xx33(C_inc0,F_real(i,j,k,1:3,1:3) & + - F_star(i,j,k,1:3,1:3)) + F_star_av = F_star_av + F_star(i,j,k,1:3,1:3) + temp33_real = F_star(i,j,k,1:3,1:3) - F_real(i,j,k,1:3,1:3) + err_f = max(err_f, sqrt(math_mul33xx33(temp33_real,temp33_real))) + enddo; enddo; enddo + P_av = math_rotate_forward33(P_av * wgt,bc(loadcase)%rotation) + write (*,'(a,/,3(3(es14.7,1x)/))',advance='no') 'P(F*) =',& + math_transpose33(P_av)/1.e6_pReal + F_star_av = F_star_av *wgt + write (*,'(a,/,3(3(es14.7,1x)/))',advance='no') 'F* =',& + math_transpose33(F_star_av) + + print '(a)', '... update stress field P(F) .....................................' + ielem = 0_pInt + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + ielem = ielem + 1_pInt + call CPFEM_general(3_pInt,& ! collect cycle + coordinates(i,j,k,1:3), F_lastInc(i,j,k,1:3,1:3),& + F_real(i,j,k,1:3,1:3),temperature(i,j,k),timeinc,ielem,1_pInt,& + sigma,dsde,P,dPdF) + enddo; enddo; enddo + + ielem = 0_pInt + err_p = 0.0_pReal + P_av =0.0_pReal + do k = 1_pInt, res(3); do j = 1_pInt, res(2); do i = 1_pInt, res(1) + ielem = ielem + 1_pInt + call CPFEM_general(2_pInt,& + coordinates(i,j,k,1:3),F_lastInc(i,j,k,1:3,1:3), & + F_real(i,j,k,1:3,1:3),temperature(i,j,k),timeinc,ielem,1_pInt,& + sigma,dsde,P,dPdF) + P_av = P_av + P + temp33_real = lambda(i,j,k,1:3,1:3) - P + err_p = max(err_p, sqrt(math_mul33xx33(temp33_real,temp33_real))) + enddo; enddo; enddo + + P_av = math_rotate_forward33(P_av * wgt,bc(loadcase)%rotation) + write (*,'(a,/,3(3(es14.7,1x)/))',advance='no') 'P(F) =',& + math_transpose33(P_av)/1.e6_pReal + + err_f = err_f/sqrt(math_mul33xx33(F_star_av,F_star_av)) + err_p = err_p/sqrt(math_mul33xx33(P_av,P_av)) + write(6,'(a,es14.7,1x)') 'error f', err_f + write(6,'(a,es14.7,1x)') 'error p', err_p + + err_crit = max(err_p, err_f) + + enddo ! end looping when convergency is achieved + print '(a)', '' + print '(a)', '==================================================================' + if(err_f > err_div_tol .or. err_stress > err_stress_tol) then + print '(A,I5.5,A)', 'increment ', totalIncsCounter, ' NOT converged' + notConvergedCounter = notConvergedCounter + 1_pInt + else + convergedCounter = convergedCounter + 1_pInt + print '(A,I5.5,A)', 'increment ', totalIncsCounter, ' converged' + endif + + if (mod(totalIncsCounter -1_pInt,bc(loadcase)%outputfrequency) == 0_pInt) then ! at output frequency + print '(a)', '' + print '(a)', '... writing results to file ......................................' + write(538) materialpoint_results(1_pInt:materialpoint_sizeResults,1,1_pInt:Npoints) ! write result to file + endif + + if( bc(loadcase)%restartFrequency > 0_pInt .and. & + mod(inc - 1_pInt,bc(loadcase)%restartFrequency) == 0_pInt) then ! at frequency of writing restart information set restart parameter for FEsolving (first call to CPFEM_general will write ToDo: true?) + restartWrite = .true. + print '(A)', 'writing converged results for restart' + call IO_write_jobBinaryFile(777,'convergedSpectralDefgrad',size(F_star)) ! writing deformation gradient field to file + write (777,rec=1) F_star + close (777) + restartInc=totalIncsCounter + endif + + + endif ! end calculation/forwarding + enddo ! end looping over incs in current loadcase + deallocate(c_reduced) + deallocate(s_reduced) + enddo ! end looping over loadcases + print '(a)', '' + print '(a)', '##################################################################' + print '(i6.6,a,i6.6,a)', notConvergedCounter, ' out of ', & + notConvergedCounter + convergedCounter, ' increments did not converge!' + close(538) + call fftw_destroy_plan(plan_lambda); call fftw_destroy_plan(plan_correction) + call quit(0_pInt) +end program DAMASK_spectral + +!******************************************************************** +! quit subroutine to satisfy IO_error +! +!******************************************************************** +subroutine quit(stop_id) + use prec + implicit none + + integer(pInt), intent(in) :: stop_id + + ! if (stop_id == 0_pInt) stop 0_pInt ! normal termination + stop 'abnormal termination of DAMASK_spectral' +end subroutine