diff --git a/code/DAMASK_spectral_driver.f90 b/code/DAMASK_spectral_driver.f90 index e7f8b301c..febaa9394 100644 --- a/code/DAMASK_spectral_driver.f90 +++ b/code/DAMASK_spectral_driver.f90 @@ -52,38 +52,40 @@ program DAMASK_spectral_Driver use numerics, only: & worldrank, & worldsize, & + stagItMax, & maxCutBack, & spectral_solver, & continueCalculation use homogenization, only: & materialpoint_sizeResults, & materialpoint_results + use material, only: & + thermal_type, & + damage_type, & + THERMAL_conduction_ID, & + DAMAGE_nonlocal_ID use DAMASK_spectral_Utilities, only: & - tBoundaryCondition, & + utilities_init, & + utilities_destroy, & tSolutionState, & - cutBack + tLoadCase, & + cutBack, & + nActiveFields, & + FIELD_UNDEFINED_ID, & + FIELD_MECH_ID, & + FIELD_THERMAL_ID, & + FIELD_DAMAGE_ID use DAMASK_spectral_SolverBasicPETSC use DAMASK_spectral_SolverAL use DAMASK_spectral_SolverPolarisation + use spectral_damage + use spectral_thermal + implicit none #include - type tLoadCase - real(pReal), dimension (3,3) :: rotation = math_I3 !< rotation of BC - type(tBoundaryCondition) :: P, & !< stress BC - deformation !< deformation BC (Fdot or L) - real(pReal) :: time = 0.0_pReal, & !< length of increment - temperature = 300.0_pReal, & !< isothermal starting conditions - density = 0.0_pReal !< density - 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/logarithmic time inc flag - logical :: followFormerTrajectory = .true. !< follow trajectory of former loadcase - end type tLoadCase - !-------------------------------------------------------------------------------------------------- ! variables related to information from load case and geom file real(pReal), dimension(9) :: temp_valueVector = 0.0_pReal !< temporarily from loadcase file when reading in tensors (initialize to 0.0) @@ -117,7 +119,7 @@ program DAMASK_spectral_Driver logical :: & guess !< guess along former trajectory integer(pInt) :: & - i, j, k, l, & + i, j, k, l, field, & errorID, & cutBackLevel = 0_pInt, & !< cut back level \f$ t = \frac{t_{inc}}{2^l} \f$ stepFraction = 0_pInt !< fraction of current time interval @@ -133,9 +135,11 @@ program DAMASK_spectral_Driver character(len=6) :: loadcase_string character(len=1024) :: incInfo !< string parsed to solution with information about current load case type(tLoadCase), allocatable, dimension(:) :: loadCases !< array of all load cases - type(tSolutionState) solres + type(tSolutionState), allocatable, dimension(:) :: solres integer(kind=MPI_OFFSET_KIND) :: my_offset integer, dimension(:), allocatable :: outputSize + integer(pInt) :: stagIter + logical :: stagIterate PetscErrorCode :: ierr external :: quit !-------------------------------------------------------------------------------------------------- @@ -147,6 +151,13 @@ program DAMASK_spectral_Driver write(6,'(a15,a)') ' Current time: ',IO_timeStamp() #include "compilation_info.f90" endif mainProcess + +!-------------------------------------------------------------------------------------------------- +! initialize field solver information + nActiveFields = 1 + if (any(thermal_type == THERMAL_conduction_ID )) nActiveFields = nActiveFields + 1 + if (any(damage_type == DAMAGE_nonlocal_ID )) nActiveFields = nActiveFields + 1 + allocate(solres(nActiveFields)) !-------------------------------------------------------------------------------------------------- ! reading basic information from load case file and allocate data structure containing load cases @@ -173,6 +184,20 @@ program DAMASK_spectral_Driver call IO_error(error_ID=837_pInt,ext_msg = trim(loadCaseFile)) ! error message for incomplete loadcase allocate (loadCases(N_n)) ! array of load cases loadCases%P%myType='p' + + do i = 1, size(loadCases) + allocate(loadCases(i)%ID(nActiveFields)) + field = 1 + loadCases(i)%ID(field) = FIELD_MECH_ID ! mechanical active by default + if (any(thermal_type == THERMAL_conduction_ID)) then ! thermal field active + field = field + 1 + loadCases(i)%ID(field) = FIELD_THERMAL_ID + endif + if (any(damage_type == DAMAGE_nonlocal_ID)) then ! damage field active + field = field + 1 + loadCases(i)%ID(field) = FIELD_DAMAGE_ID + endif + enddo !-------------------------------------------------------------------------------------------------- ! reading the load case and assign values to the allocated data structure @@ -222,8 +247,6 @@ program DAMASK_spectral_Driver loadCases(currentLoadCase)%time = IO_floatValue(line,positions,i+1_pInt) case('temp','temperature') ! starting temperature loadCases(currentLoadCase)%temperature = IO_floatValue(line,positions,i+1_pInt) - case('den','density') ! starting density - loadCases(currentLoadCase)%density = IO_floatValue(line,positions,i+1_pInt) case('n','incs','increments','steps') ! number of increments loadCases(currentLoadCase)%incs = IO_intValue(line,positions,i+1_pInt) case('logincs','logincrements','logsteps') ! number of increments (switch to log time scaling) @@ -307,7 +330,6 @@ program DAMASK_spectral_Driver write(6,'(2x,a,/,3(3(3x,f12.7,1x)/))',advance='no') 'rotation of loadframe:',& math_transpose33(loadCases(currentLoadCase)%rotation) write(6,'(2x,a,f12.6)') 'temperature:', loadCases(currentLoadCase)%temperature - write(6,'(2x,a,f12.6)') 'density: ', loadCases(currentLoadCase)%density if (loadCases(currentLoadCase)%time < 0.0_pReal) errorID = 834_pInt ! negative time increment write(6,'(2x,a,f12.6)') 'time: ', loadCases(currentLoadCase)%time if (loadCases(currentLoadCase)%incs < 1_pInt) errorID = 835_pInt ! non-positive incs count @@ -323,20 +345,36 @@ program DAMASK_spectral_Driver !-------------------------------------------------------------------------------------------------- ! doing initialization depending on selected solver - select case (spectral_solver) - case (DAMASK_spectral_SolverBasicPETSc_label) - call basicPETSc_init(loadCases(1)%temperature) - case (DAMASK_spectral_SolverAL_label) - if(iand(debug_level(debug_spectral),debug_levelBasic)/= 0 .and. worldrank == 0_pInt) & - call IO_warning(42_pInt, ext_msg='debug Divergence') - call AL_init(loadCases(1)%temperature) - case (DAMASK_spectral_SolverPolarisation_label) - if(iand(debug_level(debug_spectral),debug_levelBasic)/= 0 .and. worldrank == 0_pInt) & - call IO_warning(42_pInt, ext_msg='debug Divergence') - call Polarisation_init(loadCases(1)%temperature) - case default - call IO_error(error_ID = 891, ext_msg = trim(spectral_solver)) - end select + call Utilities_init() + do field = 1, nActiveFields + select case (loadCases(1)%ID(field)) + case(FIELD_MECH_ID) + select case (spectral_solver) + case (DAMASK_spectral_SolverBasicPETSc_label) + call basicPETSc_init(loadCases(1)%temperature) + case (DAMASK_spectral_SolverAL_label) + if(iand(debug_level(debug_spectral),debug_levelBasic)/= 0 .and. worldrank == 0_pInt) & + call IO_warning(42_pInt, ext_msg='debug Divergence') + call AL_init(loadCases(1)%temperature) + + case (DAMASK_spectral_SolverPolarisation_label) + if(iand(debug_level(debug_spectral),debug_levelBasic)/= 0 .and. worldrank == 0_pInt) & + call IO_warning(42_pInt, ext_msg='debug Divergence') + call Polarisation_init(loadCases(1)%temperature) + + case default + call IO_error(error_ID = 891, ext_msg = trim(spectral_solver)) + + end select + + case(FIELD_THERMAL_ID) + call spectral_thermal_init(loadCases(1)%temperature) + + case(FIELD_DAMAGE_ID) + call spectral_damage_init() + + end select + enddo !-------------------------------------------------------------------------------------------------- ! write header of output file @@ -442,30 +480,6 @@ program DAMASK_spectral_Driver time = time + timeinc ! forward time stepFraction = stepFraction + 1_pInt remainingLoadCaseTime = time0 - time + loadCases(currentLoadCase)%time + timeInc -!-------------------------------------------------------------------------------------------------- -! forward solution - select case(spectral_solver) - case (DAMASK_spectral_SolverBasicPETSC_label) - call BasicPETSC_forward (& - guess,timeinc,timeIncOld,remainingLoadCaseTime, & - P_BC = loadCases(currentLoadCase)%P, & - F_BC = loadCases(currentLoadCase)%deformation, & - rotation_BC = loadCases(currentLoadCase)%rotation) - - case (DAMASK_spectral_SolverAL_label) - call AL_forward (& - guess,timeinc,timeIncOld,remainingLoadCaseTime, & - P_BC = loadCases(currentLoadCase)%P, & - F_BC = loadCases(currentLoadCase)%deformation, & - rotation_BC = loadCases(currentLoadCase)%rotation) - - case (DAMASK_spectral_SolverPolarisation_label) - call Polarisation_forward (& - guess,timeinc,timeIncOld,remainingLoadCaseTime, & - P_BC = loadCases(currentLoadCase)%P, & - F_BC = loadCases(currentLoadCase)%deformation, & - rotation_BC = loadCases(currentLoadCase)%rotation) - end select !-------------------------------------------------------------------------------------------------- ! report begin of new increment @@ -485,49 +499,107 @@ program DAMASK_spectral_Driver 'Increment ',totalIncsCounter,'/',sum(loadCases%incs),& '-',stepFraction, '/', subStepFactor**cutBackLevel endif - + !-------------------------------------------------------------------------------------------------- -! calculate solution - select case(spectral_solver) - case (DAMASK_spectral_SolverBasicPETSC_label) - solres = BasicPETSC_solution (& - incInfo,guess,timeinc,timeIncOld,remainingLoadCaseTime, & - P_BC = loadCases(currentLoadCase)%P, & - F_BC = loadCases(currentLoadCase)%deformation, & - temperature_bc = loadCases(currentLoadCase)%temperature, & - rotation_BC = loadCases(currentLoadCase)%rotation, & - density = loadCases(currentLoadCase)%density) - case (DAMASK_spectral_SolverAL_label) - solres = AL_solution (& - incInfo,guess,timeinc,timeIncOld,remainingLoadCaseTime, & - P_BC = loadCases(currentLoadCase)%P, & - F_BC = loadCases(currentLoadCase)%deformation, & - temperature_bc = loadCases(currentLoadCase)%temperature, & - rotation_BC = loadCases(currentLoadCase)%rotation, & - density = loadCases(currentLoadCase)%density) - case (DAMASK_spectral_SolverPolarisation_label) - solres = Polarisation_solution (& - incInfo,guess,timeinc,timeIncOld,remainingLoadCaseTime, & - P_BC = loadCases(currentLoadCase)%P, & - F_BC = loadCases(currentLoadCase)%deformation, & - temperature_bc = loadCases(currentLoadCase)%temperature, & - rotation_BC = loadCases(currentLoadCase)%rotation, & - density = loadCases(currentLoadCase)%density) - end select +! forward fields + do field = 1, nActiveFields + select case(loadCases(currentLoadCase)%ID(field)) + case(FIELD_MECH_ID) + select case (spectral_solver) + case (DAMASK_spectral_SolverBasicPETSc_label) + call BasicPETSc_forward (& + guess,timeinc,timeIncOld,remainingLoadCaseTime, & + F_BC = loadCases(currentLoadCase)%deformation, & + P_BC = loadCases(currentLoadCase)%P, & + rotation_BC = loadCases(currentLoadCase)%rotation) + case (DAMASK_spectral_SolverAL_label) + call AL_forward (& + guess,timeinc,timeIncOld,remainingLoadCaseTime, & + F_BC = loadCases(currentLoadCase)%deformation, & + P_BC = loadCases(currentLoadCase)%P, & + rotation_BC = loadCases(currentLoadCase)%rotation) + case (DAMASK_spectral_SolverPolarisation_label) + call Polarisation_forward (& + guess,timeinc,timeIncOld,remainingLoadCaseTime, & + F_BC = loadCases(currentLoadCase)%deformation, & + P_BC = loadCases(currentLoadCase)%P, & + rotation_BC = loadCases(currentLoadCase)%rotation) + end select + + case(FIELD_THERMAL_ID) + call spectral_thermal_forward (& + guess,timeinc,timeIncOld,remainingLoadCaseTime) + + case(FIELD_DAMAGE_ID) + call spectral_damage_forward (& + guess,timeinc,timeIncOld,remainingLoadCaseTime) + end select + enddo + +!-------------------------------------------------------------------------------------------------- +! solve fields + stagIter = 0_pInt + stagIterate = .true. + do while (stagIterate) + do field = 1, nActiveFields + select case(loadCases(currentLoadCase)%ID(field)) + case(FIELD_MECH_ID) + select case (spectral_solver) + case (DAMASK_spectral_SolverBasicPETSc_label) + solres(field) = BasicPETSC_solution (& + incInfo,guess,timeinc,timeIncOld,remainingLoadCaseTime, & + P_BC = loadCases(currentLoadCase)%P, & + F_BC = loadCases(currentLoadCase)%deformation, & + temperature_bc = loadCases(currentLoadCase)%temperature, & + rotation_BC = loadCases(currentLoadCase)%rotation) + + case (DAMASK_spectral_SolverAL_label) + solres(field) = AL_solution (& + incInfo,guess,timeinc,timeIncOld,remainingLoadCaseTime, & + P_BC = loadCases(currentLoadCase)%P, & + F_BC = loadCases(currentLoadCase)%deformation, & + temperature_bc = loadCases(currentLoadCase)%temperature, & + rotation_BC = loadCases(currentLoadCase)%rotation) + + case (DAMASK_spectral_SolverPolarisation_label) + solres(field) = Polarisation_solution (& + incInfo,guess,timeinc,timeIncOld,remainingLoadCaseTime, & + P_BC = loadCases(currentLoadCase)%P, & + F_BC = loadCases(currentLoadCase)%deformation, & + temperature_bc = loadCases(currentLoadCase)%temperature, & + rotation_BC = loadCases(currentLoadCase)%rotation) + + end select + + case(FIELD_THERMAL_ID) + solres(field) = spectral_thermal_solution (& + guess,timeinc,timeIncOld,remainingLoadCaseTime) + + case(FIELD_DAMAGE_ID) + solres(field) = spectral_damage_solution (& + guess,timeinc,timeIncOld,remainingLoadCaseTime) + + end select + if(.not. solres(field)%converged) exit ! no solution found + enddo + stagIter = stagIter + 1_pInt + stagIterate = stagIter < stagItMax .and. & + all(solres(:)%converged) .and. & + .not. all(solres(:)%stagConverged) + enddo !-------------------------------------------------------------------------------------------------- ! check solution cutBack = .False. - if(solres%termIll .or. .not. solres%converged) then ! no solution found + if(solres(1)%termIll .or. .not. all(solres(:)%converged .and. solres(:)%stagConverged)) then ! no solution found if (cutBackLevel < maxCutBack) then ! do cut back if (worldrank == 0) write(6,'(/,a)') ' cut back detected' cutBack = .True. stepFraction = (stepFraction - 1_pInt) * subStepFactor ! adjust to new denominator cutBackLevel = cutBackLevel + 1_pInt time = time - timeinc ! rewind time - timeIncOld = timeinc timeinc = timeinc/2.0_pReal - elseif (solres%termIll) then ! material point model cannot find a solution, exit in any casy + elseif (solres(1)%termIll) then ! material point model cannot find a solution, exit in any casy call IO_warning(850_pInt) call quit(-1_pInt*(lastRestartWritten+1_pInt)) ! quit and provide information about last restart inc written (e.g. for regridding) elseif (continueCalculation == 1_pInt) then @@ -548,7 +620,7 @@ program DAMASK_spectral_Driver endif enddo subIncLooping cutBackLevel = max(0_pInt, cutBackLevel - 1_pInt) ! try half number of subincs next inc - if(solres%converged) then ! report converged inc + if(all(solres(:)%converged)) then ! report converged inc convergedCounter = convergedCounter + 1_pInt if (worldrank == 0) & write(6,'(/,a,'//IO_intOut(totalIncsCounter)//',a)') & @@ -593,14 +665,24 @@ program DAMASK_spectral_Driver call MPI_file_close(resUnit,ierr) close(statUnit) - select case (spectral_solver) - case (DAMASK_spectral_SolverBasicPETSC_label) - call BasicPETSC_destroy() - case (DAMASK_spectral_SolverAL_label) - call AL_destroy() - case (DAMASK_spectral_SolverPolarisation_label) - call Polarisation_destroy() - end select + do field = 1, nActiveFields + select case(loadCases(1)%ID(field)) + case(FIELD_MECH_ID) + select case (spectral_solver) + case (DAMASK_spectral_SolverBasicPETSc_label) + call BasicPETSC_destroy() + case (DAMASK_spectral_SolverAL_label) + call AL_destroy() + case (DAMASK_spectral_SolverPolarisation_label) + call Polarisation_destroy() + end select + case(FIELD_THERMAL_ID) + call spectral_thermal_destroy() + case(FIELD_DAMAGE_ID) + call spectral_damage_destroy() + end select + enddo + call utilities_destroy() call PetscFinalize(ierr); CHKERRQ(ierr) diff --git a/code/DAMASK_spectral_solverAL.f90 b/code/DAMASK_spectral_solverAL.f90 index f8836e401..729d1e820 100644 --- a/code/DAMASK_spectral_solverAL.f90 +++ b/code/DAMASK_spectral_solverAL.f90 @@ -13,7 +13,8 @@ module DAMASK_spectral_solverAL use math, only: & math_I3 use DAMASK_spectral_utilities, only: & - tSolutionState + tSolutionState, & + tSolutionParams implicit none private @@ -24,14 +25,6 @@ module DAMASK_spectral_solverAL !-------------------------------------------------------------------------------------------------- ! derived types - type tSolutionParams !< @todo use here the type definition for a full loadcase including mask - real(pReal), dimension(3,3) :: P_BC, rotation_BC - real(pReal) :: timeinc - real(pReal) :: timeincOld - real(pReal) :: temperature - real(pReal) :: density - end type tSolutionParams - type(tSolutionParams), private :: params real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal @@ -124,12 +117,9 @@ subroutine AL_init(temperature) use DAMASK_interface, only: & getSolverJobName use DAMASK_spectral_Utilities, only: & - Utilities_init, & Utilities_constitutiveResponse, & Utilities_updateGamma, & - Utilities_updateIPcoords, & - grid1Red, & - wgt + Utilities_updateIPcoords use mesh, only: & gridLocal, & gridGlobal @@ -150,7 +140,6 @@ subroutine AL_init(temperature) integer(pInt) :: proc character(len=1024) :: rankStr - call Utilities_init() if (worldrank == 0_pInt) then write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverAL init -+>>>' write(6,'(a)') ' $Id$' @@ -169,6 +158,7 @@ subroutine AL_init(temperature) !-------------------------------------------------------------------------------------------------- ! PETSc Init call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) allocate(localK(worldsize), source = 0); localK(worldrank+1) = gridLocal(3) do proc = 1, worldsize call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) @@ -182,6 +172,7 @@ subroutine AL_init(temperature) gridLocal (1),gridLocal (2),localK, & ! local grid da,ierr) ! handle, error CHKERRQ(ierr) + call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) call DMDASNESSetFunctionLocal(da,INSERT_VALUES,AL_formResidual,dummy,ierr) CHKERRQ(ierr) @@ -266,7 +257,7 @@ end subroutine AL_init !-------------------------------------------------------------------------------------------------- type(tSolutionState) function & AL_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,temperature_bc, & - rotation_BC,density) + rotation_BC) use numerics, only: & update_gamma use math, only: & @@ -287,8 +278,7 @@ type(tSolutionState) function & timeinc, & !< increment in time for current solution timeinc_old, & !< increment in time of last increment loadCaseTime, & !< remaining time of current load case - temperature_bc, & - density + temperature_bc logical, intent(in) :: & guess type(tBoundaryCondition), intent(in) :: & @@ -324,7 +314,6 @@ type(tSolutionState) function & params%timeinc = timeinc params%timeincOld = timeinc_old params%temperature = temperature_bc - params%density = density !-------------------------------------------------------------------------------------------------- ! solve BVP @@ -363,16 +352,14 @@ subroutine AL_formResidual(in,x_scal,f_scal,dummy,ierr) math_transpose33, & math_mul3333xx33, & math_invSym3333, & - math_mul33x33, & - PI + math_mul33x33 use DAMASK_spectral_Utilities, only: & wgt, & - field_realMPI, & - field_fourierMPI, & - Utilities_FFTforward, & - Utilities_fourierConvolution, & + tensorField_realMPI, & + utilities_FFTtensorForward, & + utilities_fourierGammaConvolution, & Utilities_inverseLaplace, & - Utilities_FFTbackward, & + utilities_FFTtensorBackward, & Utilities_constitutiveResponse, & Utilities_divergenceRMS, & Utilities_curlRMS @@ -444,9 +431,9 @@ subroutine AL_formResidual(in,x_scal,f_scal,dummy,ierr) !-------------------------------------------------------------------------------------------------- ! - field_realMPI = 0.0_pReal + tensorField_realMPI = 0.0_pReal do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt, gridLocal(1) - field_realMPI(1:3,1:3,i,j,k) = & + tensorField_realMPI(1:3,1:3,i,j,k) = & polarBeta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& polarAlpha*math_mul33x33(F(1:3,1:3,i,j,k), & math_mul3333xx33(C_scale,F_lambda(1:3,1:3,i,j,k) - math_I3)) @@ -455,13 +442,13 @@ subroutine AL_formResidual(in,x_scal,f_scal,dummy,ierr) !-------------------------------------------------------------------------------------------------- ! doing convolution in Fourier space - call Utilities_FFTforward() - call Utilities_fourierConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) - call Utilities_FFTbackward() + call utilities_FFTtensorForward() + call utilities_fourierGammaConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) + call utilities_FFTtensorBackward() !-------------------------------------------------------------------------------------------------- ! constructing residual - residual_F_lambda = polarBeta*F - field_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) + residual_F_lambda = polarBeta*F - tensorField_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) !-------------------------------------------------------------------------------------------------- ! evaluate constitutive response @@ -473,11 +460,11 @@ subroutine AL_formResidual(in,x_scal,f_scal,dummy,ierr) !-------------------------------------------------------------------------------------------------- ! calculate divergence - field_realMPI = 0.0_pReal - field_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = residual_F - call Utilities_FFTforward() + tensorField_realMPI = 0.0_pReal + tensorField_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = residual_F + call utilities_FFTtensorForward() err_div = Utilities_divergenceRMS() - call Utilities_FFTbackward() + call utilities_FFTtensorBackward() !-------------------------------------------------------------------------------------------------- ! constructing residual @@ -493,11 +480,11 @@ subroutine AL_formResidual(in,x_scal,f_scal,dummy,ierr) !-------------------------------------------------------------------------------------------------- ! calculating curl - field_realMPI = 0.0_pReal - field_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = F - call Utilities_FFTforward() + tensorField_realMPI = 0.0_pReal + tensorField_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = F + call utilities_FFTtensorForward() err_curl = Utilities_curlRMS() - call Utilities_FFTbackward() + call utilities_FFTtensorBackward() end subroutine AL_formResidual @@ -727,7 +714,6 @@ subroutine AL_destroy() call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) call SNESDestroy(snes,ierr); CHKERRQ(ierr) call DMDestroy(da,ierr); CHKERRQ(ierr) - call Utilities_destroy() end subroutine AL_destroy diff --git a/code/DAMASK_spectral_solverBasicPETSc.f90 b/code/DAMASK_spectral_solverBasicPETSc.f90 index bb76b80b0..46945b0da 100644 --- a/code/DAMASK_spectral_solverBasicPETSc.f90 +++ b/code/DAMASK_spectral_solverBasicPETSc.f90 @@ -13,7 +13,8 @@ module DAMASK_spectral_SolverBasicPETSc use math, only: & math_I3 use DAMASK_spectral_Utilities, only: & - tSolutionState + tSolutionState, & + tSolutionParams implicit none private @@ -24,14 +25,6 @@ module DAMASK_spectral_SolverBasicPETSc !-------------------------------------------------------------------------------------------------- ! derived types - type tSolutionParams - real(pReal), dimension(3,3) :: P_BC, rotation_BC - real(pReal) :: timeinc - real(pReal) :: timeincOld - real(pReal) :: temperature - real(pReal) :: density - end type tSolutionParams - type(tSolutionParams), private :: params !-------------------------------------------------------------------------------------------------- @@ -58,7 +51,7 @@ module DAMASK_spectral_SolverBasicPETSc C_volAvgLastInc = 0.0_pReal, & !< previous volume average stiffness C_minMaxAvg = 0.0_pReal, & !< current (min+max)/2 stiffness S = 0.0_pReal !< current compliance (filled up with zeros) - real(pReal), private :: err_stress, err_div, err_divPrev, err_divDummy + real(pReal), private :: err_stress, err_div logical, private :: ForwardData integer(pInt), private :: & totalIter = 0_pInt !< total iteration in current increment @@ -112,16 +105,13 @@ subroutine basicPETSc_init(temperature) use DAMASK_interface, only: & getSolverJobName use DAMASK_spectral_Utilities, only: & - Utilities_init, & Utilities_constitutiveResponse, & Utilities_updateGamma, & utilities_updateIPcoords, & - grid1Red, & wgt use mesh, only: & gridLocal, & - gridGlobal, & - mesh_ipCoordinates + gridGlobal use math, only: & math_invSym3333 @@ -138,7 +128,6 @@ subroutine basicPETSc_init(temperature) integer(pInt) :: proc character(len=1024) :: rankStr - call Utilities_init() mainProcess: if (worldrank == 0_pInt) then write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverBasicPETSc init -+>>>' write(6,'(a)') ' $Id$' @@ -155,6 +144,7 @@ subroutine basicPETSc_init(temperature) !-------------------------------------------------------------------------------------------------- ! initialize solver specific parts of PETSc call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) allocate(localK(worldsize), source = 0); localK(worldrank+1) = gridLocal(3) do proc = 1, worldsize call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) @@ -168,6 +158,7 @@ subroutine basicPETSc_init(temperature) gridLocal (1),gridLocal (2),localK, & ! local grid da,ierr) ! handle, error CHKERRQ(ierr) + call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) ! global solution vector (grid x 9, i.e. every def grad tensor) call DMDASNESSetFunctionLocal(da,INSERT_VALUES,BasicPETSC_formResidual,dummy,ierr) ! residual vector of same shape as solution vector CHKERRQ(ierr) @@ -205,12 +196,13 @@ subroutine basicPETSc_init(temperature) call Utilities_updateIPcoords(F) call Utilities_constitutiveResponse(F_lastInc, F, & temperature, & - 1.0_pReal, & + 0.0_pReal, & P, & C_volAvg,C_minMaxAvg, & ! global average of stiffness and (min+max)/2 temp33_Real, & .false., & math_I3) + call DMDAVecRestoreArrayF90(da,solution_vec,F,ierr); CHKERRQ(ierr) ! write data back to PETSc if (restartInc > 1_pInt) then ! using old values from files @@ -237,11 +229,10 @@ end subroutine basicPETSc_init !> @brief solution for the Basic PETSC scheme with internal iterations !-------------------------------------------------------------------------------------------------- type(tSolutionState) function basicPETSc_solution( & - incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,temperature_bc,rotation_BC,density) + incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,temperature_bc,rotation_BC) use numerics, only: & update_gamma, & - itmax, & - worldrank + itmax use DAMASK_spectral_Utilities, only: & tBoundaryCondition, & Utilities_maskedCompliance, & @@ -258,8 +249,7 @@ type(tSolutionState) function basicPETSc_solution( & timeinc, & !< increment in time for current solution timeinc_old, & !< increment in time of last increment loadCaseTime, & !< remaining time of current load case - temperature_bc, & - density + temperature_bc type(tBoundaryCondition), intent(in) :: & P_BC, & F_BC @@ -290,7 +280,6 @@ type(tSolutionState) function basicPETSc_solution( & params%timeinc = timeinc params%timeincOld = timeinc_old params%temperature = temperature_BC - params%density = density call SNESSolve(snes,PETSC_NULL_OBJECT,solution_vec,ierr); CHKERRQ(ierr) call SNESGetConvergedReason(snes,reason,ierr); CHKERRQ(ierr) @@ -329,11 +318,11 @@ subroutine BasicPETSC_formResidual(in,x_scal,f_scal,dummy,ierr) debug_spectralRotation use DAMASK_spectral_Utilities, only: & wgt, & - field_realMPI, & - field_fourierMPI, & - Utilities_FFTforward, & - Utilities_FFTbackward, & - Utilities_fourierConvolution, & + tensorField_realMPI, & + tensorField_fourierMPI, & + utilities_FFTtensorForward, & + utilities_FFTtensorBackward, & + utilities_fourierGammaConvolution, & Utilities_inverseLaplace, & Utilities_constitutiveResponse, & Utilities_divergenceRMS @@ -392,16 +381,16 @@ subroutine BasicPETSC_formResidual(in,x_scal,f_scal,dummy,ierr) !-------------------------------------------------------------------------------------------------- ! updated deformation gradient using fix point algorithm of basic scheme - field_realMPI = 0.0_pReal - field_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = f_scal - call Utilities_FFTforward() + tensorField_realMPI = 0.0_pReal + tensorField_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = f_scal + call utilities_FFTtensorForward() err_div = Utilities_divergenceRMS() - call Utilities_fourierConvolution(math_rotate_backward33(F_aim_lastIter-F_aim,params%rotation_BC)) - call Utilities_FFTbackward() + call utilities_fourierGammaConvolution(math_rotate_backward33(F_aim_lastIter-F_aim,params%rotation_BC)) + call utilities_FFTtensorBackward() !-------------------------------------------------------------------------------------------------- ! constructing residual - f_scal = field_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) + f_scal = tensorField_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) end subroutine BasicPETSc_formResidual @@ -578,7 +567,6 @@ subroutine BasicPETSc_destroy() call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) call SNESDestroy(snes,ierr); CHKERRQ(ierr) call DMDestroy(da,ierr); CHKERRQ(ierr) - call Utilities_destroy() end subroutine BasicPETSc_destroy diff --git a/code/DAMASK_spectral_solverPolarisation.f90 b/code/DAMASK_spectral_solverPolarisation.f90 index fc65e7053..874dea863 100644 --- a/code/DAMASK_spectral_solverPolarisation.f90 +++ b/code/DAMASK_spectral_solverPolarisation.f90 @@ -13,7 +13,8 @@ module DAMASK_spectral_solverPolarisation use math, only: & math_I3 use DAMASK_spectral_utilities, only: & - tSolutionState + tSolutionState, & + tSolutionParams implicit none private @@ -24,14 +25,6 @@ module DAMASK_spectral_solverPolarisation !-------------------------------------------------------------------------------------------------- ! derived types - type tSolutionParams !< @todo use here the type definition for a full loadcase including mask - real(pReal), dimension(3,3) :: P_BC, rotation_BC - real(pReal) :: timeinc - real(pReal) :: timeincOld - real(pReal) :: temperature - real(pReal) :: density - end type tSolutionParams - type(tSolutionParams), private :: params real(pReal), private, dimension(3,3) :: mask_stress = 0.0_pReal @@ -124,12 +117,9 @@ subroutine Polarisation_init(temperature) use DAMASK_interface, only: & getSolverJobName use DAMASK_spectral_Utilities, only: & - Utilities_init, & Utilities_constitutiveResponse, & Utilities_updateGamma, & - Utilities_updateIPcoords, & - grid1Red, & - wgt + Utilities_updateIPcoords use mesh, only: & gridLocal, & gridGlobal @@ -150,7 +140,6 @@ subroutine Polarisation_init(temperature) integer(pInt) :: proc character(len=1024) :: rankStr - call Utilities_init() if (worldrank == 0_pInt) then write(6,'(/,a)') ' <<<+- DAMASK_spectral_solverPolarisation init -+>>>' write(6,'(a)') ' $Id$' @@ -169,6 +158,7 @@ subroutine Polarisation_init(temperature) !-------------------------------------------------------------------------------------------------- ! PETSc Init call SNESCreate(PETSC_COMM_WORLD,snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(snes,'mech_',ierr);CHKERRQ(ierr) allocate(localK(worldsize), source = 0); localK(worldrank+1) = gridLocal(3) do proc = 1, worldsize call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) @@ -182,10 +172,10 @@ subroutine Polarisation_init(temperature) gridLocal (1),gridLocal (2),localK, & ! local grid da,ierr) ! handle, error CHKERRQ(ierr) + call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) call DMCreateGlobalVector(da,solution_vec,ierr); CHKERRQ(ierr) call DMDASNESSetFunctionLocal(da,INSERT_VALUES,Polarisation_formResidual,dummy,ierr) CHKERRQ(ierr) - call SNESSetDM(snes,da,ierr); CHKERRQ(ierr) call SNESSetConvergenceTest(snes,Polarisation_converged,dummy,PETSC_NULL_FUNCTION,ierr) CHKERRQ(ierr) call SNESSetFromOptions(snes,ierr); CHKERRQ(ierr) @@ -265,7 +255,7 @@ end subroutine Polarisation_init !-------------------------------------------------------------------------------------------------- type(tSolutionState) function & Polarisation_solution(incInfoIn,guess,timeinc,timeinc_old,loadCaseTime,P_BC,F_BC,temperature_bc, & - rotation_BC,density) + rotation_BC) use numerics, only: & update_gamma use math, only: & @@ -277,8 +267,6 @@ type(tSolutionState) function & use FEsolving, only: & restartWrite, & terminallyIll - use numerics, only: & - worldrank implicit none @@ -288,8 +276,7 @@ type(tSolutionState) function & timeinc, & !< increment in time for current solution timeinc_old, & !< increment in time of last increment loadCaseTime, & !< remaining time of current load case - temperature_bc, & - density + temperature_bc logical, intent(in) :: & guess type(tBoundaryCondition), intent(in) :: & @@ -324,7 +311,6 @@ type(tSolutionState) function & params%timeinc = timeinc params%timeincOld = timeinc_old params%temperature = temperature_bc - params%density = density !-------------------------------------------------------------------------------------------------- ! solve BVP @@ -363,16 +349,14 @@ subroutine Polarisation_formResidual(in,x_scal,f_scal,dummy,ierr) math_transpose33, & math_mul3333xx33, & math_invSym3333, & - math_mul33x33, & - PI + math_mul33x33 use DAMASK_spectral_Utilities, only: & wgt, & - field_realMPI, & - field_fourierMPI, & - Utilities_FFTforward, & - Utilities_fourierConvolution, & + tensorField_realMPI, & + utilities_FFTtensorForward, & + utilities_fourierGammaConvolution, & Utilities_inverseLaplace, & - Utilities_FFTbackward, & + utilities_FFTtensorBackward, & Utilities_constitutiveResponse, & Utilities_divergenceRMS, & Utilities_curlRMS @@ -444,9 +428,9 @@ subroutine Polarisation_formResidual(in,x_scal,f_scal,dummy,ierr) !-------------------------------------------------------------------------------------------------- ! - field_realMPI = 0.0_pReal + tensorField_realMPI = 0.0_pReal do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt, gridLocal(1) - field_realMPI(1:3,1:3,i,j,k) = & + tensorField_realMPI(1:3,1:3,i,j,k) = & polarBeta*math_mul3333xx33(C_scale,F(1:3,1:3,i,j,k) - math_I3) -& polarAlpha*math_mul33x33(F(1:3,1:3,i,j,k), & math_mul3333xx33(C_scale,F_tau(1:3,1:3,i,j,k) - F(1:3,1:3,i,j,k) - math_I3)) @@ -454,13 +438,13 @@ subroutine Polarisation_formResidual(in,x_scal,f_scal,dummy,ierr) !-------------------------------------------------------------------------------------------------- ! doing convolution in Fourier space - call Utilities_FFTforward() - call Utilities_fourierConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) - call Utilities_FFTbackward() + call utilities_FFTtensorForward() + call utilities_fourierGammaConvolution(math_rotate_backward33(polarBeta*F_aim,params%rotation_BC)) + call utilities_FFTtensorBackward() !-------------------------------------------------------------------------------------------------- ! constructing residual - residual_F_tau = polarBeta*F - field_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) + residual_F_tau = polarBeta*F - tensorField_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) !-------------------------------------------------------------------------------------------------- ! evaluate constitutive response @@ -472,11 +456,11 @@ subroutine Polarisation_formResidual(in,x_scal,f_scal,dummy,ierr) !-------------------------------------------------------------------------------------------------- ! calculate divergence - field_realMPI = 0.0_pReal - field_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = residual_F - call Utilities_FFTforward() + tensorField_realMPI = 0.0_pReal + tensorField_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = residual_F + call utilities_FFTtensorForward() err_div = Utilities_divergenceRMS() - call Utilities_FFTbackward() + call utilities_FFTtensorBackward() !-------------------------------------------------------------------------------------------------- ! constructing residual @@ -492,11 +476,11 @@ subroutine Polarisation_formResidual(in,x_scal,f_scal,dummy,ierr) !-------------------------------------------------------------------------------------------------- ! calculating curl - field_realMPI = 0.0_pReal - field_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = F - call Utilities_FFTforward() + tensorField_realMPI = 0.0_pReal + tensorField_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = F + call utilities_FFTtensorForward() err_curl = Utilities_curlRMS() - call Utilities_FFTbackward() + call utilities_FFTtensorBackward() end subroutine Polarisation_formResidual @@ -727,7 +711,6 @@ subroutine Polarisation_destroy() call VecDestroy(solution_vec,ierr); CHKERRQ(ierr) call SNESDestroy(snes,ierr); CHKERRQ(ierr) call DMDestroy(da,ierr); CHKERRQ(ierr) - call Utilities_destroy() end subroutine Polarisation_destroy diff --git a/code/DAMASK_spectral_utilities.f90 b/code/DAMASK_spectral_utilities.f90 index 30169b9bf..463568daa 100644 --- a/code/DAMASK_spectral_utilities.f90 +++ b/code/DAMASK_spectral_utilities.f90 @@ -11,6 +11,8 @@ module DAMASK_spectral_utilities use prec, only: & pReal, & pInt + use math, only: & + math_I3 implicit none private @@ -21,6 +23,18 @@ module DAMASK_spectral_utilities logical, public :: cutBack =.false. !< cut back of BVP solver in case convergence is not achieved or a material point is terminally ill integer(pInt), public, parameter :: maxPhaseFields = 2_pInt + integer(pInt), public :: nActiveFields = 0_pInt + +!-------------------------------------------------------------------------------------------------- +! field labels information + enum, bind(c) + enumerator :: FIELD_UNDEFINED_ID, & + FIELD_MECH_ID, & + FIELD_THERMAL_ID, & + FIELD_DAMAGE_ID, & + FIELD_VACANCYDIFFUSION_ID + end enum + !-------------------------------------------------------------------------------------------------- ! grid related information information real(pReal), public :: wgt !< weighting factor 1/Nelems @@ -28,37 +42,29 @@ module DAMASK_spectral_utilities !-------------------------------------------------------------------------------------------------- ! variables storing information for spectral method and FFTW integer(pInt), public :: grid1Red !< grid(1)/2 - real (C_DOUBLE), public, dimension(:,:,:,:,:), pointer :: field_realMPI !< real representation (some stress or deformation) of field_fourier - complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:,:,:), pointer :: field_fourierMPI !< field on which the Fourier transform operates + real (C_DOUBLE), public, dimension(:,:,:,:,:), pointer :: tensorField_realMPI !< real representation (some stress or deformation) of field_fourier + complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:,:,:), pointer :: tensorField_fourierMPI !< field on which the Fourier transform operates + real(C_DOUBLE), public, dimension(:,:,:,:), pointer :: vectorField_realMPI !< vector field real representation for fftw + complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:,:), pointer :: vectorField_fourierMPI !< vector field fourier representation for fftw + real(C_DOUBLE), public, dimension(:,:,:), pointer :: scalarField_realMPI !< scalar field real representation for fftw + complex(C_DOUBLE_COMPLEX),public, dimension(:,:,:), pointer :: scalarField_fourierMPI !< scalar field fourier representation for fftw real(pReal), private, dimension(:,:,:,:,:,:,:), allocatable :: gamma_hat !< gamma operator (field) for spectral method real(pReal), private, dimension(:,:,:,:), allocatable :: xi !< wave vector field for divergence and for gamma operator - real(pReal), private, dimension(3,3,3,3) :: C_ref !< reference stiffness - real(pReal), private, dimension(3) :: scaledGeomSize !< scaled geometry size for calculation of divergence (Basic, Basic PETSc) - -!-------------------------------------------------------------------------------------------------- -! debug fftw - real(C_DOUBLE), private, dimension(:,:,:), pointer :: scalarField_realMPI !< scalar field real representation for debugging fftw - complex(C_DOUBLE_COMPLEX),private, dimension(:,:,:), pointer :: scalarField_fourierMPI !< scalar field fourier representation for debugging fftw + real(pReal), private, dimension(3,3,3,3) :: C_ref !< mechanic reference stiffness + real(pReal), protected, public, dimension(3) :: scaledGeomSize !< scaled geometry size for calculation of divergence (Basic, Basic PETSc) -!-------------------------------------------------------------------------------------------------- -! geometry reconstruction - real(C_DOUBLE), private, dimension(:,:,:,:), pointer :: coords_realMPI !< vector field real representation for geometry reconstruction - complex(C_DOUBLE_COMPLEX),private, dimension(:,:,:,:), pointer :: coords_fourierMPI !< vector field fourier representation for geometry reconstruction - -!-------------------------------------------------------------------------------------------------- -! debug divergence - real(C_DOUBLE), private, dimension(:,:,:,:), pointer :: divRealMPI !< vector field real representation for debugging divergence calculation - complex(C_DOUBLE_COMPLEX),private, dimension(:,:,:,:), pointer :: divFourierMPI !< vector field fourier representation for debugging divergence calculation - !-------------------------------------------------------------------------------------------------- ! plans for FFTW type(C_PTR), private :: & - planForthMPI, & !< FFTW MPI plan P(x) to P(k) - planBackMPI, & !< FFTW MPI plan F(k) to F(x) + planTensorForthMPI, & !< FFTW MPI plan P(x) to P(k) + planTensorBackMPI, & !< FFTW MPI plan F(k) to F(x) + planVectorForthMPI, & !< FFTW MPI plan P(x) to P(k) + planVectorBackMPI, & !< FFTW MPI plan F(k) to F(x) + planScalarForthMPI, & !< FFTW MPI plan P(x) to P(k) + planScalarBackMPI, & !< FFTW MPI plan F(k) to F(x) planDebugForthMPI, & !< FFTW MPI plan for scalar field planDebugBackMPI, & !< FFTW MPI plan for scalar field inverse - planDivMPI, & !< FFTW MPI plan for FFTW in case of debugging divergence calculation - planCoordsMPI !< FFTW MPI plan for geometry reconstruction + planDivMPI !< FFTW MPI plan for FFTW in case of debugging divergence calculation !-------------------------------------------------------------------------------------------------- ! variables controlling debugging @@ -74,6 +80,7 @@ module DAMASK_spectral_utilities type, public :: tSolutionState !< return type of solution from spectral solver variants logical :: converged = .true. logical :: regrid = .false. + logical :: stagConverged = .true. logical :: termIll = .false. integer(pInt) :: iterationsNeeded = 0_pInt end type tSolutionState @@ -85,6 +92,30 @@ module DAMASK_spectral_utilities character(len=64) :: myType = 'None' end type tBoundaryCondition + type, public :: tLoadCase + real(pReal), dimension (3,3) :: rotation = math_I3 !< rotation of BC + type(tBoundaryCondition) :: P, & !< stress BC + deformation !< deformation BC (Fdot or L) + 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/logarithmic time inc flag + logical :: followFormerTrajectory = .true. !< follow trajectory of former loadcase + integer(kind(FIELD_UNDEFINED_ID)), allocatable :: ID(:) + end type tLoadCase + + type, public :: tSolutionParams !< @todo use here the type definition for a full loadcase including mask + real(pReal), dimension(3,3) :: P_BC, rotation_BC + real(pReal) :: timeinc + real(pReal) :: timeincOld + real(pReal) :: temperature + real(pReal) :: density + end type tSolutionParams + + type(tSolutionParams), private :: params + type, public :: phaseFieldDataBin !< set of parameters defining a phase field real(pReal) :: diffusion = 0.0_pReal, & !< thermal conductivity mobility = 0.0_pReal, & !< thermal mobility @@ -96,18 +127,29 @@ module DAMASK_spectral_utilities public :: & utilities_init, & utilities_updateGamma, & - utilities_FFTforward, & - utilities_FFTbackward, & - utilities_fourierConvolution, & + utilities_FFTtensorForward, & + utilities_FFTtensorBackward, & + utilities_FFTvectorForward, & + utilities_FFTvectorBackward, & + utilities_FFTscalarForward, & + utilities_FFTscalarBackward, & + utilities_fourierGammaConvolution, & + utilities_fourierGreenConvolution, & utilities_inverseLaplace, & utilities_divergenceRMS, & utilities_curlRMS, & + utilities_fourierScalarGradient, & + utilities_fourierVectorDivergence, & utilities_maskedCompliance, & utilities_constitutiveResponse, & utilities_calculateRate, & utilities_forwardField, & utilities_destroy, & - utilities_updateIPcoords + utilities_updateIPcoords, & + FIELD_UNDEFINED_ID, & + FIELD_MECH_ID, & + FIELD_THERMAL_ID, & + FIELD_DAMAGE_ID private :: & utilities_getFilter @@ -123,15 +165,12 @@ contains !-------------------------------------------------------------------------------------------------- subroutine utilities_init() use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) - use DAMASK_interface, only: & - geometryFile use IO, only: & IO_error, & IO_warning, & IO_timeStamp, & IO_open_file - use numerics, only: & - DAMASK_NumThreadsInt, & + use numerics, only: & fftw_planner_flag, & fftw_timelimit, & memory_efficient, & @@ -155,9 +194,7 @@ subroutine utilities_init() gridGlobal, & gridLocal, & gridOffset, & - geomSizeGlobal, & - geomSizeLocal, & - geomSizeOffset + geomSizeGlobal implicit none #ifdef PETSc @@ -168,13 +205,11 @@ subroutine utilities_init() PetscErrorCode :: ierr #endif integer(pInt) :: i, j, k - integer(pInt), parameter :: fileUnit = 228_pInt integer(pInt), dimension(3) :: k_s type(C_PTR) :: & tensorFieldMPI, & !< field cotaining data for FFTW in real and fourier space (in place) - scalarFieldMPI, & !< field cotaining data for FFTW in real space when debugging FFTW (no in place) - div, & !< field cotaining data for FFTW in real and fourier space when debugging divergence (in place) - coordsMPI + vectorFieldMPI, & !< field cotaining data for FFTW in real space when debugging FFTW (no in place) + scalarFieldMPI !< field cotaining data for FFTW in real space when debugging FFTW (no in place) integer(C_INTPTR_T) :: gridFFTW(3), alloc_local, local_K, local_K_offset integer(C_INTPTR_T), parameter :: & scalarSize = 1_C_INTPTR_T, & @@ -236,65 +271,76 @@ subroutine utilities_init() gridFFTW = int(gridGlobal,C_INTPTR_T) alloc_local = fftw_mpi_local_size_3d(gridFFTW(3), gridFFTW(2), gridFFTW(1)/2 +1, & MPI_COMM_WORLD, local_K, local_K_offset) - tensorFieldMPI = fftw_alloc_complex(9*alloc_local) - call c_f_pointer(tensorFieldMPI, field_realMPI, [3_C_INTPTR_T,3_C_INTPTR_T, & - 2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T),gridFFTW(2),local_K]) - call c_f_pointer(tensorFieldMPI, field_fourierMPI, [3_C_INTPTR_T,3_C_INTPTR_T, & - gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T , gridFFTW(2),local_K]) + + tensorFieldMPI = fftw_alloc_complex(tensorSize*alloc_local) + call c_f_pointer(tensorFieldMPI, tensorField_realMPI, [3_C_INTPTR_T,3_C_INTPTR_T, & + 2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T),gridFFTW(2),local_K]) ! place a pointer for a real tensor representation + call c_f_pointer(tensorFieldMPI, tensorField_fourierMPI, [3_C_INTPTR_T,3_C_INTPTR_T, & + gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T , gridFFTW(2),local_K]) ! place a pointer for a fourier tensor representation + + vectorFieldMPI = fftw_alloc_complex(vecSize*alloc_local) + call c_f_pointer(vectorFieldMPI, vectorField_realMPI, [3_C_INTPTR_T,& + 2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T),gridFFTW(2),local_K]) ! place a pointer for a real vector representation + call c_f_pointer(vectorFieldMPI, vectorField_fourierMPI,[3_C_INTPTR_T,& + gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T, gridFFTW(2),local_K]) ! place a pointer for a fourier vector representation + + scalarFieldMPI = fftw_alloc_complex(scalarSize*alloc_local) ! allocate data for real representation (no in place transform) + call c_f_pointer(scalarFieldMPI, scalarField_realMPI, & + [2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1),gridFFTW(2),local_K]) ! place a pointer for a real scalar representation + call c_f_pointer(scalarFieldMPI, scalarField_fourierMPI, & + [ gridFFTW(1)/2_C_INTPTR_T + 1 ,gridFFTW(2),local_K]) ! place a pointer for a fourier scarlar representation allocate (xi(3,grid1Red,gridLocal(2),gridLocal(3)),source = 0.0_pReal) ! frequencies, only half the size for first dimension - coordsMPI = fftw_alloc_complex(3*alloc_local) - call c_f_pointer(coordsMPI, coords_realMPI, [3_C_INTPTR_T,& - 2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T),gridFFTW(2),local_K]) ! place a pointer for a real representation on coords_fftw - call c_f_pointer(coordsMPI, coords_fourierMPI,[3_C_INTPTR_T,& - gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T, gridFFTW(2),local_K]) ! place a pointer for a real representation on coords_fftw - !-------------------------------------------------------------------------------------------------- -! MPI fftw plans - planForthMPI = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], tensorSize, & ! dimension, logical length in each dimension in reversed order, no. of transforms - FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! default iblock and oblock - field_realMPI, field_fourierMPI, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision - planBackMPI = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], tensorSize, & ! dimension, logical length in each dimension in reversed order, no. of transforms - FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! default iblock and oblock - field_fourierMPI,field_realMPI, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! all processors, planer precision +! tensor MPI fftw plans + planTensorForthMPI = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + tensorSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock + tensorField_realMPI, tensorField_fourierMPI, &! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision + planTensorBackMPI = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + tensorSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock + tensorField_fourierMPI,tensorField_realMPI, &! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! all processors, planer precision !-------------------------------------------------------------------------------------------------- -! Coordinates MPI fftw plans - planCoordsMPI = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], vecSize, & ! dimension, logical length in each dimension in reversed order, no. of transforms - FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! default iblock and oblock - coords_fourierMPI,coords_realMPI, & ! input data, output data - MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision - +! vector MPI fftw plans + planVectorForthMPI = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + vecSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, &! no. of transforms, default iblock and oblock + vectorField_realMPI, vectorField_fourierMPI, &! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision + planVectorBackMPI = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + vecSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock + vectorField_fourierMPI,vectorField_realMPI, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! all processors, planer precision + +!-------------------------------------------------------------------------------------------------- +! scalar MPI fftw plans + planScalarForthMPI = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order + scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock + scalarField_realMPI, scalarField_fourierMPI, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision + planScalarBackMPI = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & ! dimension, logical length in each dimension in reversed order, no. of transforms + scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & ! no. of transforms, default iblock and oblock + scalarField_fourierMPI,scalarField_realMPI, & ! input data, output data + MPI_COMM_WORLD, fftw_planner_flag) ! use all processors, planer precision !-------------------------------------------------------------------------------------------------- ! depending on debug options, allocate more memory and create additional plans if (debugDivergence) then - div = fftw_alloc_complex(3*alloc_local) - call c_f_pointer(div,divRealMPI, [3_C_INTPTR_T,& - 2_C_INTPTR_T*(gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T),gridFFTW(2),local_K]) - call c_f_pointer(div,divFourierMPI,[3_C_INTPTR_T,& - gridFFTW(1)/2_C_INTPTR_T + 1_C_INTPTR_T, gridFFTW(2),local_K]) planDivMPI = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2) ,gridFFTW(1)],vecSize, & FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & - divFourierMPI, divRealMPI, & + vectorField_fourierMPI, vectorField_realMPI, & MPI_COMM_WORLD, fftw_planner_flag) endif if (debugFFTW) then - scalarFieldMPI = fftw_alloc_complex(alloc_local) ! allocate data for real representation (no in place transform) - call c_f_pointer(scalarFieldMPI, scalarField_realMPI, & - [2*(gridFFTW(1)/2 + 1),gridFFTW(2),local_K]) ! place a pointer for a real representation - call c_f_pointer(scalarFieldMPI, scalarField_fourierMPI, & - [ gridFFTW(1)/2 + 1 ,gridFFTW(2),local_K]) ! place a pointer for a fourier representation planDebugForthMPI = fftw_mpi_plan_many_dft_r2c(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & - scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & - scalarField_realMPI, scalarField_fourierMPI, & - MPI_COMM_WORLD, fftw_planner_flag) + scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & + scalarField_realMPI, scalarField_fourierMPI, & + MPI_COMM_WORLD, fftw_planner_flag) planDebugBackMPI = fftw_mpi_plan_many_dft_c2r(3, [gridFFTW(3),gridFFTW(2),gridFFTW(1)], & - scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & - scalarField_fourierMPI,scalarField_realMPI, & - MPI_COMM_WORLD, fftw_planner_flag) + scalarSize, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, & + scalarField_fourierMPI,scalarField_realMPI, & + MPI_COMM_WORLD, fftw_planner_flag) endif !-------------------------------------------------------------------------------------------------- ! general initialization of FFTW (see manual on fftw.org for more details) @@ -320,7 +366,7 @@ subroutine utilities_init() if(memory_efficient) then ! allocate just single fourth order tensor allocate (gamma_hat(3,3,3,3,1,1,1), source = 0.0_pReal) else ! precalculation of gamma_hat field - allocate (gamma_hat(3,3,3,3,grid1Red,gridLocal(2),gridLocal(3)), source = 0.0_pReal) + allocate (gamma_hat(3,3,3,3,grid1Red,gridLocal(2),gridLocal(3)), source = 0.0_pReal) endif end subroutine utilities_init @@ -345,8 +391,6 @@ subroutine utilities_updateGamma(C,saveReference) gridLocal use math, only: & math_inv33 - use mesh, only: & - gridLocal implicit none real(pReal), intent(in), dimension(3,3,3,3) :: C !< input stiffness to store as reference stiffness @@ -383,14 +427,13 @@ subroutine utilities_updateGamma(C,saveReference) end subroutine utilities_updateGamma - !-------------------------------------------------------------------------------------------------- !> @brief forward FFT of data in field_real to field_fourier with highest freqs. removed !> @details Does an unweighted FFT transform from real to complex. !> In case of debugging the FFT, also one component of the tensor (specified by row and column) !> is independetly transformed complex to complex and compared to the whole tensor transform !-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTforward() +subroutine utilities_FFTtensorForward() use math use numerics, only: & worldrank @@ -398,10 +441,6 @@ subroutine utilities_FFTforward() gridLocal implicit none - external :: & - MPI_Bcast, & - MPI_reduce - integer(pInt) :: row, column ! if debug FFTW, compare 3D array field of row and column real(pReal), dimension(2) :: myRand, maxScalarField ! random numbers integer(pInt) :: i, j, k @@ -419,12 +458,12 @@ subroutine utilities_FFTforward() call MPI_Bcast(column,1,MPI_INTEGER,0,PETSC_COMM_WORLD,ierr) scalarField_realMPI = 0.0_pReal scalarField_realMPI(1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = & - field_realMPI(row,column,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) ! store the selected component + tensorField_realMPI(row,column,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) ! store the selected component endif !-------------------------------------------------------------------------------------------------- ! doing the FFT - call fftw_mpi_execute_dft_r2c(planForthMPI,field_realMPI,field_fourierMPI) + call fftw_mpi_execute_dft_r2c(planTensorForthMPI,tensorField_realMPI,tensorField_fourierMPI) !-------------------------------------------------------------------------------------------------- ! comparing 1 and 3x3 FT results @@ -433,10 +472,10 @@ subroutine utilities_FFTforward() where(abs(scalarField_fourierMPI(1:grid1Red,1:gridLocal(2),1:gridLocal(3))) > tiny(1.0_pReal)) ! avoid division by zero scalarField_fourierMPI(1:grid1Red,1:gridLocal(2),1:gridLocal(3)) = & (scalarField_fourierMPI(1:grid1Red,1:gridLocal(2),1:gridLocal(3))-& - field_fourierMPI(row,column,1:grid1Red,1:gridLocal(2),1:gridLocal(3)))/& + tensorField_fourierMPI(row,column,1:grid1Red,1:gridLocal(2),1:gridLocal(3)))/& scalarField_fourierMPI(1:grid1Red,1:gridLocal(2),1:gridLocal(3)) else where - scalarField_fourierMPI = cmplx(0.0,0.0,pReal) + scalarField_realMPI = cmplx(0.0,0.0,pReal) end where maxScalarField(1) = maxval(real (scalarField_fourierMPI(1:grid1Red,1:gridLocal(2), & 1:gridLocal(3)))) @@ -454,11 +493,11 @@ subroutine utilities_FFTforward() !-------------------------------------------------------------------------------------------------- ! applying filter do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,grid1Red - field_fourierMPI(1:3,1:3,i,j,k) = cmplx(utilities_getFilter(xi(1:3,i,j,k)),0.0,pReal)* & - field_fourierMPI(1:3,1:3,i,j,k) + tensorField_fourierMPI(1:3,1:3,i,j,k) = utilities_getFilter(xi(1:3,i,j,k))* & + tensorField_fourierMPI(1:3,1:3,i,j,k) enddo; enddo; enddo -end subroutine utilities_FFTforward +end subroutine utilities_FFTtensorForward !-------------------------------------------------------------------------------------------------- @@ -468,7 +507,7 @@ end subroutine utilities_FFTforward !> is independetly transformed complex to complex and compared to the whole tensor transform !> results is weighted by number of points stored in wgt !-------------------------------------------------------------------------------------------------- -subroutine utilities_FFTbackward() +subroutine utilities_FFTtensorBackward() use math use numerics, only: & worldrank @@ -476,10 +515,6 @@ subroutine utilities_FFTbackward() gridLocal implicit none - external :: & - MPI_Bcast, & - MPI_reduce - integer(pInt) :: row, column !< if debug FFTW, compare 3D array field of row and column real(pReal), dimension(2) :: myRand real(pReal) :: maxScalarField @@ -496,12 +531,12 @@ subroutine utilities_FFTbackward() call MPI_Bcast(row ,1,MPI_INTEGER,0,PETSC_COMM_WORLD,ierr) call MPI_Bcast(column,1,MPI_INTEGER,0,PETSC_COMM_WORLD,ierr) scalarField_fourierMPI(1:grid1Red,1:gridLocal(2),1:gridLocal(3)) = & - field_fourierMPI(row,column,1:grid1Red,1:gridLocal(2),1:gridLocal(3)) + tensorField_fourierMPI(row,column,1:grid1Red,1:gridLocal(2),1:gridLocal(3)) endif !-------------------------------------------------------------------------------------------------- ! doing the iFFT - call fftw_mpi_execute_dft_c2r(planBackMPI,field_fourierMPI,field_realMPI) ! back transform of fluct deformation gradient + call fftw_mpi_execute_dft_c2r(planTensorBackMPI,tensorField_fourierMPI,tensorField_realMPI) ! back transform of fluct deformation gradient !-------------------------------------------------------------------------------------------------- ! comparing 1 and 3x3 inverse FT results @@ -510,10 +545,10 @@ subroutine utilities_FFTbackward() where(abs(real(scalarField_realMPI,pReal)) > tiny(1.0_pReal)) ! avoid division by zero scalarField_realMPI(1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = & (scalarField_realMPI(1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) & - - field_realMPI (row,column,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)))/ & + - tensorField_realMPI (row,column,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)))/ & scalarField_realMPI(1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) else where - scalarField_realMPI = 0.0_pReal + scalarField_realMPI = cmplx(0.0,0.0,pReal) end where maxScalarField = maxval(real (scalarField_realMPI(1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)))) call MPI_reduce(MPI_IN_PLACE,maxScalarField,1,MPI_DOUBLE,MPI_MAX,0,PETSC_COMM_WORLD,ierr) @@ -524,10 +559,91 @@ subroutine utilities_FFTbackward() endif endif - field_realMPI = field_realMPI * wgt ! normalize the result by number of elements + tensorField_realMPI = tensorField_realMPI * wgt ! normalize the result by number of elements -end subroutine utilities_FFTbackward +end subroutine utilities_FFTtensorBackward +!-------------------------------------------------------------------------------------------------- +!> @brief forward FFT of data in field_real to field_fourier with highest freqs. removed +!> @details Does an unweighted FFT transform from real to complex. +!> In case of debugging the FFT, also one component of the scalar +!> is independetly transformed complex to complex and compared to the whole scalar transform +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTscalarForward() + use math + use mesh, only: & + gridLocal + + integer(pInt) :: i, j, k + +! doing the scalar FFT + call fftw_mpi_execute_dft_r2c(planScalarForthMPI,scalarField_realMPI,scalarField_fourierMPI) + +! applying filter + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,grid1Red + scalarField_fourierMPI(i,j,k) = utilities_getFilter(xi(1:3,i,j,k))* & + scalarField_fourierMPI(i,j,k) + enddo; enddo; enddo + +end subroutine utilities_FFTscalarForward + +!-------------------------------------------------------------------------------------------------- +!> @brief backward FFT of data in field_fourier to field_real +!> @details Does an inverse FFT transform from complex to real +!> In case of debugging the FFT, also one component of the scalar +!> is independetly transformed complex to complex and compared to the whole scalar transform +!> results is weighted by number of points stored in wgt +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTscalarBackward() + use math + +! doing the scalar iFFT + call fftw_mpi_execute_dft_c2r(planScalarBackMPI,scalarField_fourierMPI,scalarField_realMPI) + + scalarField_realMPI = scalarField_realMPI * wgt ! normalize the result by number of elements + +end subroutine utilities_FFTscalarBackward + +!-------------------------------------------------------------------------------------------------- +!> @brief forward FFT of data in field_real to field_fourier with highest freqs. removed +!> @details Does an unweighted FFT transform from real to complex. +!> In case of debugging the FFT, also one component of the vector +!> is independetly transformed complex to complex and compared to the whole vector transform +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTvectorForward() + use math + use mesh, only: & + gridLocal + + integer(pInt) :: i, j, k + +! doing the vecotr FFT + call fftw_mpi_execute_dft_r2c(planVectorForthMPI,vectorField_realMPI,vectorField_fourierMPI) + +! applying filter + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,grid1Red + vectorField_fourierMPI(1:3,i,j,k) = utilities_getFilter(xi(1:3,i,j,k))* & + vectorField_fourierMPI(1:3,i,j,k) + enddo; enddo; enddo + +end subroutine utilities_FFTvectorForward + +!-------------------------------------------------------------------------------------------------- +!> @brief backward FFT of data in field_fourier to field_real +!> @details Does an inverse FFT transform from complex to real +!> In case of debugging the FFT, also one component of the vector +!> is independetly transformed complex to complex and compared to the whole vector transform +!> results is weighted by number of points stored in wgt +!-------------------------------------------------------------------------------------------------- +subroutine utilities_FFTvectorBackward() + use math + +! doing the vector iFFT + call fftw_mpi_execute_dft_c2r(planVectorBackMPI,vectorField_fourierMPI,vectorField_realMPI) + + vectorField_realMPI = vectorField_realMPI * wgt ! normalize the result by number of elements + +end subroutine utilities_FFTvectorBackward !-------------------------------------------------------------------------------------------------- !> @brief doing convolution with inverse laplace kernel @@ -554,13 +670,14 @@ subroutine utilities_inverseLaplace() do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt, grid1Red k_s = xi(1:3,i,j,k)*scaledGeomSize - if (any(k_s /= 0_pInt)) field_fourierMPI(1:3,1:3,i,j,k-gridOffset) = & - field_fourierMPI(1:3,1:3,i,j,k-gridOffset)/ & + if (any(k_s /= 0_pInt)) tensorField_fourierMPI(1:3,1:3,i,j,k-gridOffset) = & + tensorField_fourierMPI(1:3,1:3,i,j,k-gridOffset)/ & cmplx(-sum((2.0_pReal*PI*k_s/geomSizeGlobal)* & - (2.0_pReal*PI*k_s/geomSizeGlobal)),0.0_pReal,pReal) + (2.0_pReal*PI*k_s/geomSizeGlobal)),0.0_pReal,pReal) enddo; enddo; enddo + if (gridOffset == 0_pInt) & - field_fourierMPI(1:3,1:3,1,1,1) = cmplx(0.0_pReal,0.0_pReal,pReal) + tensorField_fourierMPI(1:3,1:3,1,1,1) = cmplx(0.0_pReal,0.0_pReal,pReal) end subroutine utilities_inverseLaplace @@ -568,7 +685,7 @@ end subroutine utilities_inverseLaplace !-------------------------------------------------------------------------------------------------- !> @brief doing convolution gamma_hat * field_real, ensuring that average value = fieldAim !-------------------------------------------------------------------------------------------------- -subroutine utilities_fourierConvolution(fieldAim) +subroutine utilities_fourierGammaConvolution(fieldAim) use numerics, only: & memory_efficient use math, only: & @@ -583,12 +700,13 @@ subroutine utilities_fourierConvolution(fieldAim) real(pReal), intent(in), dimension(3,3) :: fieldAim !< desired average value of the field after convolution real(pReal), dimension(3,3) :: xiDyad, temp33_Real complex(pReal), dimension(3,3) :: temp33_complex + integer(pInt) :: & i, j, k, & l, m, n, o if (worldrank == 0_pInt) then - write(6,'(/,a)') ' ... doing convolution .....................................................' + write(6,'(/,a)') ' ... doing gamma convolution ................................................' flush(6) endif @@ -605,22 +723,59 @@ subroutine utilities_fourierConvolution(fieldAim) forall(l=1_pInt:3_pInt, m=1_pInt:3_pInt, n=1_pInt:3_pInt, o=1_pInt:3_pInt)& gamma_hat(l,m,n,o, 1,1,1) = temp33_Real(l,n)*xiDyad(m,o) forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - temp33_Complex(l,m) = sum(gamma_hat(l,m,1:3,1:3, 1,1,1) * field_fourierMPI(1:3,1:3,i,j,k)) - field_fourierMPI(1:3,1:3,i,j,k) = temp33_Complex + temp33_Complex(l,m) = sum(gamma_hat(l,m,1:3,1:3, 1,1,1) * & + tensorField_fourierMPI(1:3,1:3,i,j,k)) + tensorField_fourierMPI(1:3,1:3,i,j,k) = temp33_Complex endif enddo; enddo; enddo else ! use precalculated gamma-operator do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,grid1Red forall(l = 1_pInt:3_pInt, m = 1_pInt:3_pInt) & - temp33_Complex(l,m) = sum(gamma_hat(l,m,1:3,1:3,i,j,k) * field_fourierMPI(1:3,1:3,i,j,k)) - field_fourierMPI(1:3,1:3,i,j,k) = temp33_Complex + temp33_Complex(l,m) = sum(gamma_hat(l,m,1:3,1:3,i,j,k) * & + tensorField_fourierMPI(1:3,1:3,i,j,k)) + tensorField_fourierMPI(1:3,1:3,i,j,k) = temp33_Complex enddo; enddo; enddo endif - if (gridOffset == 0_pInt) & - field_fourierMPI(1:3,1:3,1,1,1) = cmplx(fieldAim/wgt,0.0_pReal,pReal) ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 - -end subroutine utilities_fourierConvolution + if (gridOffset == 0_pInt) & + tensorField_fourierMPI(1:3,1:3,1,1,1) = cmplx(fieldAim/wgt,0.0_pReal,pReal) ! singular point at xi=(0.0,0.0,0.0) i.e. i=j=k=1 + +end subroutine utilities_fourierGammaConvolution + +!-------------------------------------------------------------------------------------------------- +!> @brief doing convolution DamageGreenOp_hat * field_real +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierGreenConvolution(D_ref, mobility_ref, deltaT) + + use numerics, only: & + memory_efficient + use math, only: & + math_mul33x3, & + PI + use numerics, only: & + worldrank + use mesh, only: & + gridLocal, & + geomSizeGlobal + + implicit none + real(pReal), dimension(3,3), intent(in) :: D_ref !< desired average value of the field after convolution + real(pReal), intent(in) :: mobility_ref, deltaT !< desired average value of the field after convolution + real(pReal), dimension(3) :: k_s + real(pReal) :: GreenOp_hat + integer(pInt) :: i, j, k + +!-------------------------------------------------------------------------------------------------- +! do the actual spectral method calculation + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2) ;do i = 1_pInt, grid1Red + k_s = xi(1:3,i,j,k)*scaledGeomSize + GreenOp_hat = 1.0_pReal/ & + (mobility_ref + deltaT*sum((2.0_pReal*PI*k_s/geomSizeGlobal)* & + math_mul33x3(D_ref,(2.0_pReal*PI*k_s/geomSizeGlobal))))!< GreenOp_hat = iK^{T} * D_ref * iK, K is frequency + scalarField_fourierMPI(i,j,k) = scalarField_fourierMPI(i,j,k)*GreenOp_hat + enddo; enddo; enddo + +end subroutine utilities_fourierGreenConvolution !-------------------------------------------------------------------------------------------------- !> @brief calculate root mean square of divergence of field_fourier @@ -634,10 +789,6 @@ real(pReal) function utilities_divergenceRMS() gridGlobal implicit none - external :: & - MPI_reduce, & - MPI_Allreduce - integer(pInt) :: i, j, k real(pReal) :: & err_real_div_RMS, & !< RMS of divergence in real space @@ -658,19 +809,19 @@ real(pReal) function utilities_divergenceRMS() do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2) do i = 2_pInt, grid1Red -1_pInt ! Has somewhere a conj. complex counterpart. Therefore count it twice. utilities_divergenceRMS = utilities_divergenceRMS & - + 2.0_pReal*(sum (real(math_mul33x3_complex(field_fourierMPI(1:3,1:3,i,j,k),& ! (sqrt(real(a)**2 + aimag(a)**2))**2 = real(a)**2 + aimag(a)**2. do not take square root and square again + + 2.0_pReal*(sum (real(math_mul33x3_complex(tensorField_fourierMPI(1:3,1:3,i,j,k),& ! (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_fourierMPI(1:3,1:3,i,j,k),& + +sum(aimag(math_mul33x3_complex(tensorField_fourierMPI(1:3,1:3,i,j,k),& xi(1:3,i,j,k))*TWOPIIMG)**2.0_pReal)) enddo utilities_divergenceRMS = utilities_divergenceRMS & ! these two layers (DC and Nyquist) do not have a conjugate complex counterpart (if grid(1) /= 1) - + sum( real(math_mul33x3_complex(field_fourierMPI(1:3,1:3,1 ,j,k), & + + sum( real(math_mul33x3_complex(tensorField_fourierMPI(1:3,1:3,1 ,j,k), & xi(1:3,1 ,j,k))*TWOPIIMG)**2.0_pReal) & - + sum(aimag(math_mul33x3_complex(field_fourierMPI(1:3,1:3,1 ,j,k), & + + sum(aimag(math_mul33x3_complex(tensorField_fourierMPI(1:3,1:3,1 ,j,k), & xi(1:3,1 ,j,k))*TWOPIIMG)**2.0_pReal) & - + sum( real(math_mul33x3_complex(field_fourierMPI(1:3,1:3,grid1Red,j,k), & + + sum( real(math_mul33x3_complex(tensorField_fourierMPI(1:3,1:3,grid1Red,j,k), & xi(1:3,grid1Red,j,k))*TWOPIIMG)**2.0_pReal) & - + sum(aimag(math_mul33x3_complex(field_fourierMPI(1:3,1:3,grid1Red,j,k), & + + sum(aimag(math_mul33x3_complex(tensorField_fourierMPI(1:3,1:3,grid1Red,j,k), & xi(1:3,grid1Red,j,k))*TWOPIIMG)**2.0_pReal) enddo; enddo if(gridGlobal(1) == 1_pInt) utilities_divergenceRMS = utilities_divergenceRMS * 0.5_pReal ! counted twice in case of grid(1) == 1 @@ -682,19 +833,19 @@ real(pReal) function utilities_divergenceRMS() if (debugDivergence) then ! calculate divergence again err_div_max = 0.0_pReal do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt, grid1Red - temp3_Complex = math_mul33x3_complex(field_fourierMPI(1:3,1:3,i,j,k)*wgt,& ! weighting P_fourier + temp3_Complex = math_mul33x3_complex(tensorField_fourierMPI(1:3,1:3,i,j,k)*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)) - divFourierMPI(1:3,i,j,k) = temp3_Complex ! need divergence NOT squared + vectorField_fourierMPI(1:3,i,j,k) = temp3_Complex ! need divergence NOT squared enddo; enddo; enddo - call fftw_mpi_execute_dft_c2r(planDivMPI,divFourierMPI,divRealMPI) ! already weighted + call fftw_mpi_execute_dft_c2r(planDivMPI,vectorField_fourierMPI,vectorField_realMPI) ! already weighted - err_real_div_RMS = sum(divRealMPI**2.0_pReal) + err_real_div_RMS = sum(vectorField_realMPI**2.0_pReal) call MPI_reduce(MPI_IN_PLACE,err_real_div_RMS,1,MPI_DOUBLE,MPI_SUM,0,PETSC_COMM_WORLD,ierr) err_real_div_RMS = sqrt(wgt*err_real_div_RMS) ! RMS in real space - err_real_div_max = maxval(sum(divRealMPI**2.0_pReal,dim=4)) ! max in real space + err_real_div_max = maxval(sum(vectorField_realMPI**2.0_pReal,dim=4)) ! max in real space call MPI_reduce(MPI_IN_PLACE,err_real_div_max,1,MPI_DOUBLE,MPI_MAX,0,PETSC_COMM_WORLD,ierr) err_real_div_max = sqrt(err_real_div_max) @@ -725,9 +876,6 @@ real(pReal) function utilities_curlRMS() gridGlobal implicit none - external :: & - MPI_Allreduce - integer(pInt) :: i, j, k, l complex(pReal), dimension(3,3) :: curl_fourier PetscErrorCode :: ierr @@ -744,33 +892,33 @@ real(pReal) function utilities_curlRMS() do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 2_pInt, grid1Red - 1_pInt do l = 1_pInt, 3_pInt - curl_fourier(l,1) = (+field_fourierMPI(l,3,i,j,k)*xi(2,i,j,k)& - -field_fourierMPI(l,2,i,j,k)*xi(3,i,j,k))*TWOPIIMG - curl_fourier(l,2) = (+field_fourierMPI(l,1,i,j,k)*xi(3,i,j,k)& - -field_fourierMPI(l,3,i,j,k)*xi(1,i,j,k))*TWOPIIMG - curl_fourier(l,3) = (+field_fourierMPI(l,2,i,j,k)*xi(1,i,j,k)& - -field_fourierMPI(l,1,i,j,k)*xi(2,i,j,k))*TWOPIIMG + curl_fourier(l,1) = (+tensorField_fourierMPI(l,3,i,j,k)*xi(2,i,j,k)& + -tensorField_fourierMPI(l,2,i,j,k)*xi(3,i,j,k))*TWOPIIMG + curl_fourier(l,2) = (+tensorField_fourierMPI(l,1,i,j,k)*xi(3,i,j,k)& + -tensorField_fourierMPI(l,3,i,j,k)*xi(1,i,j,k))*TWOPIIMG + curl_fourier(l,3) = (+tensorField_fourierMPI(l,2,i,j,k)*xi(1,i,j,k)& + -tensorField_fourierMPI(l,1,i,j,k)*xi(2,i,j,k))*TWOPIIMG enddo utilities_curlRMS = utilities_curlRMS + & 2.0_pReal*sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal) enddo do l = 1_pInt, 3_pInt - curl_fourier = (+field_fourierMPI(l,3,1,j,k)*xi(2,1,j,k)& - -field_fourierMPI(l,2,1,j,k)*xi(3,1,j,k))*TWOPIIMG - curl_fourier = (+field_fourierMPI(l,1,1,j,k)*xi(3,1,j,k)& - -field_fourierMPI(l,3,1,j,k)*xi(1,1,j,k))*TWOPIIMG - curl_fourier = (+field_fourierMPI(l,2,1,j,k)*xi(1,1,j,k)& - -field_fourierMPI(l,1,1,j,k)*xi(2,1,j,k))*TWOPIIMG + curl_fourier = (+tensorField_fourierMPI(l,3,1,j,k)*xi(2,1,j,k)& + -tensorField_fourierMPI(l,2,1,j,k)*xi(3,1,j,k))*TWOPIIMG + curl_fourier = (+tensorField_fourierMPI(l,1,1,j,k)*xi(3,1,j,k)& + -tensorField_fourierMPI(l,3,1,j,k)*xi(1,1,j,k))*TWOPIIMG + curl_fourier = (+tensorField_fourierMPI(l,2,1,j,k)*xi(1,1,j,k)& + -tensorField_fourierMPI(l,1,1,j,k)*xi(2,1,j,k))*TWOPIIMG enddo utilities_curlRMS = utilities_curlRMS + & 2.0_pReal*sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal) do l = 1_pInt, 3_pInt - curl_fourier = (+field_fourierMPI(l,3,grid1Red,j,k)*xi(2,grid1Red,j,k)& - -field_fourierMPI(l,2,grid1Red,j,k)*xi(3,grid1Red,j,k))*TWOPIIMG - curl_fourier = (+field_fourierMPI(l,1,grid1Red,j,k)*xi(3,grid1Red,j,k)& - -field_fourierMPI(l,3,grid1Red,j,k)*xi(1,grid1Red,j,k))*TWOPIIMG - curl_fourier = (+field_fourierMPI(l,2,grid1Red,j,k)*xi(1,grid1Red,j,k)& - -field_fourierMPI(l,1,grid1Red,j,k)*xi(2,grid1Red,j,k))*TWOPIIMG + curl_fourier = (+tensorField_fourierMPI(l,3,grid1Red,j,k)*xi(2,grid1Red,j,k)& + -tensorField_fourierMPI(l,2,grid1Red,j,k)*xi(3,grid1Red,j,k))*TWOPIIMG + curl_fourier = (+tensorField_fourierMPI(l,1,grid1Red,j,k)*xi(3,grid1Red,j,k)& + -tensorField_fourierMPI(l,3,grid1Red,j,k)*xi(1,grid1Red,j,k))*TWOPIIMG + curl_fourier = (+tensorField_fourierMPI(l,2,grid1Red,j,k)*xi(1,grid1Red,j,k)& + -tensorField_fourierMPI(l,1,grid1Red,j,k)*xi(2,grid1Red,j,k))*TWOPIIMG enddo utilities_curlRMS = utilities_curlRMS + & 2.0_pReal*sum(real(curl_fourier)**2.0_pReal + aimag(curl_fourier)**2.0_pReal) @@ -884,6 +1032,48 @@ function utilities_maskedCompliance(rot_BC,mask_stress,C) end function utilities_maskedCompliance +!-------------------------------------------------------------------------------------------------- +!> @brief calculate scalar gradient in fourier field +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierScalarGradient() + use math, only: & + PI + use mesh, only: & + gridLocal, & + geomSizeGlobal + integer(pInt) :: i, j, k + + vectorField_fourierMPI = cmplx(0.0_pReal,0.0_pReal,pReal) + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,grid1Red + vectorField_fourierMPI(1:3,i,j,k) = scalarField_fourierMPI(i,j,k)* & + cmplx(0.0_pReal,2.0_pReal*PI*xi(1:3,i,j,k)* & + scaledGeomSize/geomSizeGlobal,pReal) + enddo; enddo; enddo +end subroutine utilities_fourierScalarGradient + + +!-------------------------------------------------------------------------------------------------- +!> @brief calculate vector divergence in fourier field +!-------------------------------------------------------------------------------------------------- +subroutine utilities_fourierVectorDivergence() + use math, only: & + PI + use mesh, only: & + gridLocal, & + geomSizeGlobal + integer(pInt) :: i, j, k, m + + scalarField_fourierMPI = cmplx(0.0_pReal,0.0_pReal,pReal) + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,grid1Red + do m = 1_pInt, 3_pInt + scalarField_fourierMPI(i,j,k) = & + scalarField_fourierMPI(i,j,k) + & + vectorField_fourierMPI(m,i,j,k)* & + cmplx(0.0_pReal,2.0_pReal*PI*xi(m,i,j,k)*scaledGeomSize(m)/geomSizeGlobal(m),pReal) + enddo + enddo; enddo; enddo +end subroutine utilities_fourierVectorDivergence + !-------------------------------------------------------------------------------------------------- !> @brief calculates constitutive response !-------------------------------------------------------------------------------------------------- @@ -912,14 +1102,8 @@ subroutine utilities_constitutiveResponse(F_lastInc,F,temperature,timeinc,& materialpoint_F, & materialpoint_P, & materialpoint_dPdF -! use thermal_isothermal, only: & -! thermal_isothermal_temperature implicit none - external :: & - MPI_reduce, & - MPI_Allreduce - real(pReal), intent(in) :: temperature !< temperature (no field) real(pReal), intent(in), dimension(3,3,gridLocal(1),gridLocal(2),gridLocal(3)) :: & F_lastInc, & !< target deformation gradient @@ -955,9 +1139,8 @@ subroutine utilities_constitutiveResponse(F_lastInc,F,temperature,timeinc,& call CPFEM_general(CPFEM_COLLECT,F_lastInc(1:3,1:3,1,1,1),F(1:3,1:3,1,1,1), & temperature,timeinc,1_pInt,1_pInt) -! thermal_isothermal_temperature(:) = temperature - materialpoint_F = reshape(F,[3,3,1,product(gridLocal)]) + materialpoint_F = reshape(F,[3,3,1,product(gridLocal)]) call debug_reset() !-------------------------------------------------------------------------------------------------- @@ -978,7 +1161,7 @@ subroutine utilities_constitutiveResponse(F_lastInc,F,temperature,timeinc,& flush(6) endif endif - + call CPFEM_general(calcMode,F_lastInc(1:3,1:3,1,1,1), F(1:3,1:3,1,1,1), & ! first call calculates everything temperature,timeinc,1_pInt,1_pInt) @@ -1062,9 +1245,6 @@ function utilities_forwardField(timeinc,field_lastInc,rate,aim) gridLocal implicit none - external :: & - MPI_Allreduce - real(pReal), intent(in) :: & timeinc !< timeinc of current step real(pReal), intent(in), dimension(3,3,gridLocal(1),gridLocal(2),gridLocal(3)) :: & @@ -1083,7 +1263,7 @@ function utilities_forwardField(timeinc,field_lastInc,rate,aim) call MPI_Allreduce(MPI_IN_PLACE,fieldDiff,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) fieldDiff = fieldDiff - aim utilities_forwardField = utilities_forwardField - & - spread(spread(spread(fieldDiff,3,gridLocal(1)),4,gridLocal(2)),5,gridLocal(3)) + spread(spread(spread(fieldDiff,3,gridLocal(1)),4,gridLocal(2)),5,gridLocal(3)) endif end function utilities_forwardField @@ -1122,11 +1302,13 @@ real(pReal) function utilities_getFilter(k) utilities_getFilter = 0.0_pReal if (gridGlobal(2) /= 1_pInt .and. k(2) == real(gridGlobal(2)/2_pInt, pReal)/scaledGeomSize(2)) & utilities_getFilter = 0.0_pReal ! do not delete the whole slice in case of 2D calculation - if (gridGlobal(2) /= 1_pInt .and. k(2) == real(gridGlobal(2)/2_pInt + mod(gridGlobal(2),2_pInt), pReal)/scaledGeomSize(2)) & + if (gridGlobal(2) /= 1_pInt .and. & + k(2) == real(gridGlobal(2)/2_pInt + mod(gridGlobal(2),2_pInt), pReal)/scaledGeomSize(2)) & utilities_getFilter = 0.0_pReal ! do not delete the whole slice in case of 2D calculation if (gridGlobal(3) /= 1_pInt .and. k(3) == real(gridGlobal(3)/2_pInt, pReal)/scaledGeomSize(3)) & utilities_getFilter = 0.0_pReal ! do not delete the whole slice in case of 2D calculation - if (gridGlobal(3) /= 1_pInt .and. k(3) == real(gridGlobal(3)/2_pInt + mod(gridGlobal(3),2_pInt), pReal)/scaledGeomSize(3)) & + if (gridGlobal(3) /= 1_pInt .and. & + k(3) == real(gridGlobal(3)/2_pInt + mod(gridGlobal(3),2_pInt), pReal)/scaledGeomSize(3)) & utilities_getFilter = 0.0_pReal ! do not delete the whole slice in case of 2D calculation end function utilities_getFilter @@ -1143,9 +1325,12 @@ subroutine utilities_destroy() if (debugDivergence) call fftw_destroy_plan(planDivMPI) if (debugFFTW) call fftw_destroy_plan(planDebugForthMPI) if (debugFFTW) call fftw_destroy_plan(planDebugBackMPI) - call fftw_destroy_plan(planForthMPI) - call fftw_destroy_plan(planBackMPI) - call fftw_destroy_plan(planCoordsMPI) + call fftw_destroy_plan(planTensorForthMPI) + call fftw_destroy_plan(planTensorBackMPI) + call fftw_destroy_plan(planVectorForthMPI) + call fftw_destroy_plan(planVectorBackMPI) + call fftw_destroy_plan(planScalarForthMPI) + call fftw_destroy_plan(planScalarBackMPI) end subroutine utilities_destroy @@ -1164,8 +1349,6 @@ subroutine utilities_updateIPcoords(F) geomSizeGlobal, & mesh_ipCoordinates implicit none - external :: & - MPI_Bcast real(pReal), dimension(3,3,gridLocal(1),gridLocal(2),gridLocal(3)), intent(in) :: F integer(pInt) :: i, j, k, m @@ -1173,40 +1356,41 @@ subroutine utilities_updateIPcoords(F) real(pReal), dimension(3,3) :: Favg PetscErrorCode :: ierr - field_realMPI = 0.0_pReal - field_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = F - call utilities_FFTforward() + tensorField_realMPI = 0.0_pReal + tensorField_realMPI(1:3,1:3,1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = F + call utilities_FFTtensorForward() integrator = geomSizeGlobal * 0.5_pReal / PI step = geomSizeGlobal/real(gridGlobal, pReal) !-------------------------------------------------------------------------------------------------- ! average F - if (gridOffset == 0_pInt) Favg = real(field_fourierMPI(1:3,1:3,1,1,1),pReal)*wgt + if (gridOffset == 0_pInt) Favg = real(tensorField_fourierMPI(1:3,1:3,1,1,1),pReal)*wgt call MPI_Bcast(Favg,9,MPI_DOUBLE,0,PETSC_COMM_WORLD,ierr) !-------------------------------------------------------------------------------------------------- ! integration in Fourier space - coords_fourierMPI = cmplx(0.0_pReal, 0.0_pReal, pReal) + vectorField_fourierMPI = cmplx(0.0_pReal, 0.0_pReal, pReal) do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,grid1Red do m = 1_pInt,3_pInt - coords_fourierMPI(m,i,j,k) = sum(field_fourierMPI(m,1:3,i,j,k)*& - cmplx(0.0_pReal,xi(1:3,i,j,k)*scaledGeomSize*integrator,pReal)) + vectorField_fourierMPI(m,i,j,k) = sum(tensorField_fourierMPI(m,1:3,i,j,k)*& + cmplx(0.0_pReal,xi(1:3,i,j,k)*scaledGeomSize*integrator,pReal)) enddo - if (any(xi(1:3,i,j,k) /= 0.0_pReal)) coords_fourierMPI(1:3,i,j,k) = & - coords_fourierMPI(1:3,i,j,k)/cmplx(-sum(xi(1:3,i,j,k)*scaledGeomSize*xi(1:3,i,j,k)* & + if (any(xi(1:3,i,j,k) /= 0.0_pReal)) & + vectorField_fourierMPI(1:3,i,j,k) = & + vectorField_fourierMPI(1:3,i,j,k)/cmplx(-sum(xi(1:3,i,j,k)*scaledGeomSize*xi(1:3,i,j,k)* & scaledGeomSize),0.0_pReal,pReal) enddo; enddo; enddo - call fftw_mpi_execute_dft_c2r(planCoordsMPI,coords_fourierMPI,coords_realMPI) + call fftw_mpi_execute_dft_c2r(planVectorBackMPI,vectorField_fourierMPI,vectorField_realMPI) !-------------------------------------------------------------------------------------------------- ! add average to fluctuation and put (0,0,0) on (0,0,0) - if (gridOffset == 0_pInt) offset_coords = coords_realMPI(1:3,1,1,1) + if (gridOffset == 0_pInt) offset_coords = vectorField_realMPI(1:3,1,1,1) call MPI_Bcast(offset_coords,3,MPI_DOUBLE,0,PETSC_COMM_WORLD,ierr) offset_coords = math_mul33x3(Favg,step/2.0_pReal) - offset_coords m = 1_pInt do k = 1_pInt,gridLocal(3); do j = 1_pInt,gridLocal(2); do i = 1_pInt,gridLocal(1) - mesh_ipCoordinates(1:3,1,m) = coords_realMPI(1:3,i,j,k) & + mesh_ipCoordinates(1:3,1,m) = vectorField_realMPI(1:3,i,j,k) & + offset_coords & + math_mul33x3(Favg,step*real([i,j,k+gridOffset]-1_pInt,pReal)) m = m+1_pInt diff --git a/code/Makefile b/code/Makefile index af7b8d2d8..179d7b7fd 100644 --- a/code/Makefile +++ b/code/Makefile @@ -348,7 +348,8 @@ DAMASK_spectral.exe: MESHNAME := mesh.f90 DAMASK_spectral.exe: INTERFACENAME := DAMASK_spectral_interface.f90 -SPECTRAL_SOLVER_FILES = DAMASK_spectral_solverAL.o DAMASK_spectral_solverBasicPETSc.o DAMASK_spectral_solverPolarisation.o +SPECTRAL_SOLVER_FILES = DAMASK_spectral_solverAL.o DAMASK_spectral_solverBasicPETSc.o DAMASK_spectral_solverPolarisation.o \ + spectral_thermal.o spectral_damage.o SPECTRAL_FILES = prec.o DAMASK_interface.o IO.o libs.o numerics.o debug.o math.o \ FEsolving.o mesh.o material.o lattice.o \ @@ -379,6 +380,12 @@ DAMASK_spectral_solverPolarisation.o: DAMASK_spectral_solverPolarisation.f90 DAMASK_spectral_solverBasicPETSc.o: DAMASK_spectral_solverBasicPETSc.f90 \ DAMASK_spectral_utilities.o +spectral_thermal.o: spectral_thermal.f90 \ + DAMASK_spectral_utilities.o + +spectral_damage.o: spectral_damage.f90 \ + DAMASK_spectral_utilities.o + DAMASK_spectral_utilities.o: DAMASK_spectral_utilities.f90 \ CPFEM.o diff --git a/code/numerics.f90 b/code/numerics.f90 index 9ba61854b..dc26a6aa1 100644 --- a/code/numerics.f90 +++ b/code/numerics.f90 @@ -115,8 +115,9 @@ module numerics spectral_solver = 'basicpetsc' , & !< spectral solution method spectral_filter = 'none' !< spectral filtering method character(len=1024), protected, public :: & - petsc_options = '-snes_type ngmres & - &-snes_ngmres_anderson ' + petsc_options = '-mech_snes_type ngmres & + &-damage_snes_type ngmres & + &-thermal_snes_type ngmres ' integer(pInt), protected, public :: & fftw_planner_flag = 32_pInt, & !< conversion of fftw_plan_mode to integer, basically what is usually done in the include file of fftw continueCalculation = 0_pInt, & !< 0: exit if BVP solver does not converge, 1: continue calculation if BVP solver does not converge diff --git a/code/spectral_damage.f90 b/code/spectral_damage.f90 new file mode 100644 index 000000000..2f8d35fd1 --- /dev/null +++ b/code/spectral_damage.f90 @@ -0,0 +1,409 @@ +!-------------------------------------------------------------------------------------------------- +! $Id: spectral_damage.f90 4082 2015-04-11 20:28:07Z MPIE\m.diehl $ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Shaokang Zhang, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Spectral solver for nonlocal damage +!-------------------------------------------------------------------------------------------------- +module spectral_damage + use prec, only: & + pInt, & + pReal + use math, only: & + math_I3 + use DAMASK_spectral_Utilities, only: & + tSolutionState, & + tSolutionParams + use numerics, only: & + worldrank, & + worldsize + + implicit none + private +#include + + character (len=*), parameter, public :: & + spectral_damage_label = 'spectraldamage' + +!-------------------------------------------------------------------------------------------------- +! derived types + type(tSolutionParams), private :: params + +!-------------------------------------------------------------------------------------------------- +! PETSc data + SNES, private :: damage_snes + Vec, private :: solution + PetscInt, private :: xstart, xend, ystart, yend, zstart, zend + real(pReal), private, dimension(:,:,:), allocatable :: & + damage_current, & !< field of current damage + damage_lastInc, & !< field of previous damage + damage_stagInc !< field of staggered damage + +!-------------------------------------------------------------------------------------------------- +! reference diffusion tensor, mobility etc. + integer(pInt), private :: totalIter = 0_pInt !< total iteration in current increment + real(pReal), dimension(3,3), private :: D_ref + real(pReal), private :: mobility_ref + character(len=1024), private :: incInfo + + public :: & + spectral_damage_init, & + spectral_damage_solution, & + spectral_damage_forward, & + spectral_damage_destroy + external :: & + VecDestroy, & + DMDestroy, & + DMDACreate3D, & + DMCreateGlobalVector, & + DMDASNESSetFunctionLocal, & + PETScFinalize, & + SNESDestroy, & + SNESGetNumberFunctionEvals, & + SNESGetIterationNumber, & + SNESSolve, & + SNESSetDM, & + SNESGetConvergedReason, & + SNESSetConvergenceTest, & + SNESSetFromOptions, & + SNESCreate, & + MPI_Abort, & + MPI_Bcast, & + MPI_Allreduce + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields and fills them with data, potentially from restart info +!-------------------------------------------------------------------------------------------------- +subroutine spectral_damage_init() + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_intOut, & + IO_read_realFile, & + IO_timeStamp + use DAMASK_spectral_Utilities, only: & + wgt + use mesh, only: & + gridLocal, & + gridGlobal + use damage_nonlocal, only: & + damage_nonlocal_getDiffusion33, & + damage_nonlocal_getMobility + + implicit none + DM :: damage_grid + Vec :: uBound, lBound + PetscErrorCode :: ierr + PetscObject :: dummy + integer(pInt), dimension(:), allocatable :: localK + integer(pInt) :: proc + integer(pInt) :: i, j, k, cell + character(len=100) :: snes_type + + mainProcess: if (worldrank == 0_pInt) then + write(6,'(/,a)') ' <<<+- spectral_damage init -+>>>' + write(6,'(a)') ' $Id: spectral_damage.f90 4082 2015-04-11 20:28:07Z MPIE\m.diehl $' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +!-------------------------------------------------------------------------------------------------- +! initialize solver specific parts of PETSc + call SNESCreate(PETSC_COMM_WORLD,damage_snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(damage_snes,'damage_',ierr);CHKERRQ(ierr) + allocate(localK(worldsize), source = 0); localK(worldrank+1) = gridLocal(3) + do proc = 1, worldsize + call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) + enddo + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & !< cut off stencil at boundary + DMDA_STENCIL_BOX, & !< Moore (26) neighborhood around central point + gridGlobal(1),gridGlobal(2),gridGlobal(3), & !< global grid + 1, 1, worldsize, & + 1, 0, & !< #dof (damage phase field), ghost boundary width (domain overlap) + gridLocal (1),gridLocal (2),localK, & !< local grid + damage_grid,ierr) !< handle, error + CHKERRQ(ierr) + call SNESSetDM(damage_snes,damage_grid,ierr); CHKERRQ(ierr) !< connect snes to da + call DMCreateGlobalVector(damage_grid,solution,ierr); CHKERRQ(ierr) !< global solution vector (grid x 1, i.e. every def grad tensor) + call DMDASNESSetFunctionLocal(damage_grid,INSERT_VALUES,spectral_damage_formResidual,dummy,ierr) !< residual vector of same shape as solution vector + CHKERRQ(ierr) + call SNESSetFromOptions(damage_snes,ierr); CHKERRQ(ierr) !< pull it all together with additional cli arguments + call SNESGetType(damage_snes,snes_type,ierr); CHKERRQ(ierr) + if (trim(snes_type) == 'vinewtonrsls' .or. & + trim(snes_type) == 'vinewtonssls') then + call DMGetGlobalVector(damage_grid,lBound,ierr); CHKERRQ(ierr) + call DMGetGlobalVector(damage_grid,uBound,ierr); CHKERRQ(ierr) + call VecSet(lBound,0.0,ierr); CHKERRQ(ierr) + call VecSet(uBound,1.0,ierr); CHKERRQ(ierr) + call SNESVISetVariableBounds(damage_snes,lBound,uBound,ierr) !< variable bounds for variational inequalities like contact mechanics, damage etc. + call DMRestoreGlobalVector(damage_grid,lBound,ierr); CHKERRQ(ierr) + call DMRestoreGlobalVector(damage_grid,uBound,ierr); CHKERRQ(ierr) + endif + +!-------------------------------------------------------------------------------------------------- +! init fields + call DMDAGetCorners(damage_grid,xstart,ystart,zstart,xend,yend,zend,ierr) + CHKERRQ(ierr) + xend = xstart + xend - 1 + yend = ystart + yend - 1 + zend = zstart + zend - 1 + call VecSet(solution,1.0,ierr); CHKERRQ(ierr) + allocate(damage_current(gridLocal(1),gridLocal(2),gridLocal(3)), source=1.0_pReal) + allocate(damage_lastInc(gridLocal(1),gridLocal(2),gridLocal(3)), source=1.0_pReal) + allocate(damage_stagInc(gridLocal(1),gridLocal(2),gridLocal(3)), source=1.0_pReal) + +!-------------------------------------------------------------------------------------------------- +! damage reference diffusion update + cell = 0_pInt + D_ref = 0.0_pReal + mobility_ref = 0.0_pReal + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,gridLocal(1) + cell = cell + 1_pInt + D_ref = D_ref + damage_nonlocal_getDiffusion33(1,cell) + mobility_ref = mobility_ref + damage_nonlocal_getMobility(1,cell) + enddo; enddo; enddo + D_ref = D_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + mobility_ref = mobility_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + +end subroutine spectral_damage_init + +!-------------------------------------------------------------------------------------------------- +!> @brief solution for the spectral damage scheme with internal iterations +!-------------------------------------------------------------------------------------------------- +type(tSolutionState) function spectral_damage_solution(guess,timeinc,timeinc_old,loadCaseTime) + use numerics, only: & + itmax, & + err_damage_tolAbs, & + err_damage_tolRel + use DAMASK_spectral_Utilities, only: & + tBoundaryCondition, & + Utilities_maskedCompliance, & + Utilities_updateGamma + use mesh, only: & + gridLocal + use damage_nonlocal, only: & + damage_nonlocal_putNonLocalDamage + + implicit none + +!-------------------------------------------------------------------------------------------------- +! input data for solution + real(pReal), intent(in) :: & + timeinc, & !< increment in time for current solution + timeinc_old, & !< increment in time of last increment + loadCaseTime !< remaining time of current load case + logical, intent(in) :: guess + integer(pInt) :: i, j, k, cell + PetscInt ::position + PetscReal :: minDamage, maxDamage, stagNorm, solnNorm + +!-------------------------------------------------------------------------------------------------- +! PETSc Data + PetscErrorCode :: ierr + SNESConvergedReason :: reason + + spectral_damage_solution%converged =.false. + +!-------------------------------------------------------------------------------------------------- +! set module wide availabe data + params%timeinc = timeinc + params%timeincOld = timeinc_old + + call SNESSolve(damage_snes,PETSC_NULL_OBJECT,solution,ierr); CHKERRQ(ierr) + call SNESGetConvergedReason(damage_snes,reason,ierr); CHKERRQ(ierr) + + if (reason < 1) then + spectral_damage_solution%converged = .false. + spectral_damage_solution%iterationsNeeded = itmax + else + spectral_damage_solution%converged = .true. + spectral_damage_solution%iterationsNeeded = totalIter + endif + stagNorm = maxval(abs(damage_current - damage_stagInc)) + solnNorm = maxval(abs(damage_current)) + call MPI_Allreduce(MPI_IN_PLACE,stagNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + call MPI_Allreduce(MPI_IN_PLACE,solnNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + damage_stagInc = damage_current + spectral_damage_solution%stagConverged = stagNorm < err_damage_tolAbs & + .or. stagNorm < err_damage_tolRel*solnNorm + +!-------------------------------------------------------------------------------------------------- +! updating damage state + cell = 0_pInt !< material point = 0 + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,gridLocal(1) + cell = cell + 1_pInt !< material point increase + call damage_nonlocal_putNonLocalDamage(damage_current(i,j,k),1,cell) + enddo; enddo; enddo + + call VecMin(solution,position,minDamage,ierr); CHKERRQ(ierr) + call VecMax(solution,position,maxDamage,ierr); CHKERRQ(ierr) + if (worldrank == 0) then + if (spectral_damage_solution%converged) & + write(6,'(/,a)') ' ... nonlocal damage converged .....................................' + write(6,'(/,a,f8.6,2x,f8.6,2x,f8.6,/)',advance='no') ' Minimum|Maximum|Delta Damage = ',& + minDamage, maxDamage, stagNorm + write(6,'(/,a)') ' ===========================================================================' + flush(6) + endif + +end function spectral_damage_solution + + +!-------------------------------------------------------------------------------------------------- +!> @brief forms the spectral damage residual vector +!-------------------------------------------------------------------------------------------------- +subroutine spectral_damage_formResidual(in,x_scal,f_scal,dummy,ierr) + use mesh, only: & + gridLocal + use math, only: & + math_mul33x3 + use DAMASK_spectral_Utilities, only: & + scalarField_realMPI, & + vectorField_realMPI, & + utilities_FFTvectorForward, & + utilities_FFTvectorBackward, & + utilities_FFTscalarForward, & + utilities_FFTscalarBackward, & + utilities_fourierGreenConvolution, & + utilities_fourierScalarGradient, & + utilities_fourierVectorDivergence + use damage_nonlocal, only: & + damage_nonlocal_getSourceAndItsTangent,& + damage_nonlocal_getDiffusion33, & + damage_nonlocal_getMobility + + implicit none + DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & + in + PetscScalar, dimension( & + XG_RANGE,YG_RANGE,ZG_RANGE) :: & + x_scal + PetscScalar, dimension( & + X_RANGE,Y_RANGE,Z_RANGE) :: & + f_scal + PetscObject :: dummy + PetscErrorCode :: ierr + integer(pInt) :: i, j, k, cell + real(pReal) :: phiDot, dPhiDot_dPhi, mobility + + damage_current = x_scal +!-------------------------------------------------------------------------------------------------- +! evaluate polarization field + scalarField_realMPI = 0.0_pReal + scalarField_realMPI(1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = damage_current + call utilities_FFTscalarForward() + call utilities_fourierScalarGradient() !< calculate gradient of damage field + call utilities_FFTvectorBackward() + cell = 0_pInt + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,gridLocal(1) + cell = cell + 1_pInt + vectorField_realMPI(1:3,i,j,k) = math_mul33x3(damage_nonlocal_getDiffusion33(1,cell) - D_ref, & + vectorField_realMPI(1:3,i,j,k)) + enddo; enddo; enddo + call utilities_FFTvectorForward() + call utilities_fourierVectorDivergence() !< calculate damage divergence in fourier field + call utilities_FFTscalarBackward() + cell = 0_pInt + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,gridLocal(1) + cell = cell + 1_pInt + call damage_nonlocal_getSourceAndItsTangent(phiDot, dPhiDot_dPhi, damage_current(i,j,k), 1, cell) + mobility = damage_nonlocal_getMobility(1,cell) + scalarField_realMPI(i,j,k) = params%timeinc*scalarField_realMPI(i,j,k) + & + params%timeinc*phiDot + & + mobility*damage_lastInc(i,j,k) - & + mobility*damage_current(i,j,k) + & + mobility_ref*damage_current(i,j,k) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! convolution of damage field with green operator + call utilities_FFTscalarForward() + call utilities_fourierGreenConvolution(D_ref, mobility_ref, params%timeinc) + call utilities_FFTscalarBackward() + where(scalarField_realMPI > 1.0_pReal) scalarField_realMPI = 1.0_pReal + where(scalarField_realMPI < 0.0_pReal) scalarField_realMPI = 0.0_pReal + +!-------------------------------------------------------------------------------------------------- +! constructing residual + f_scal = scalarField_realMPI(1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) - & + damage_current + +end subroutine spectral_damage_formResidual + +!-------------------------------------------------------------------------------------------------- +!> @brief spectral damage forwarding routine +!-------------------------------------------------------------------------------------------------- +subroutine spectral_damage_forward(guess,timeinc,timeinc_old,loadCaseTime) + use mesh, only: & + gridLocal + use DAMASK_spectral_Utilities, only: & + cutBack, & + wgt + use damage_nonlocal, only: & + damage_nonlocal_putNonLocalDamage, & + damage_nonlocal_getDiffusion33, & + damage_nonlocal_getMobility + + implicit none + real(pReal), intent(in) :: & + timeinc_old, & + timeinc, & + loadCaseTime !< remaining time of current load case + logical, intent(in) :: guess + PetscErrorCode :: ierr + integer(pInt) :: i, j, k, cell + DM :: dm_local + PetscScalar, dimension(:,:,:), pointer :: x_scal + + if (cutBack) then + damage_current = damage_lastInc + damage_stagInc = damage_lastInc +!-------------------------------------------------------------------------------------------------- +! reverting damage field state + cell = 0_pInt + call SNESGetDM(damage_snes,dm_local,ierr); CHKERRQ(ierr) + call DMDAVecGetArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with + x_scal(xstart:xend,ystart:yend,zstart:zend) = damage_current + call DMDAVecRestoreArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,gridLocal(1) + cell = cell + 1_pInt + call damage_nonlocal_putNonLocalDamage(damage_current(i,j,k),1,cell) + enddo; enddo; enddo + else +!-------------------------------------------------------------------------------------------------- +! update rate and forward last inc + damage_lastInc = damage_current + cell = 0_pInt + D_ref = 0.0_pReal + mobility_ref = 0.0_pReal + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,gridLocal(1) + cell = cell + 1_pInt + D_ref = D_ref + damage_nonlocal_getDiffusion33(1,cell) + mobility_ref = mobility_ref + damage_nonlocal_getMobility(1,cell) + enddo; enddo; enddo + D_ref = D_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + mobility_ref = mobility_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + endif + + end subroutine spectral_damage_forward + +!-------------------------------------------------------------------------------------------------- +!> @brief destroy routine +!-------------------------------------------------------------------------------------------------- +subroutine spectral_damage_destroy() + + implicit none + PetscErrorCode :: ierr + + call VecDestroy(solution,ierr); CHKERRQ(ierr) + call SNESDestroy(damage_snes,ierr); CHKERRQ(ierr) + +end subroutine spectral_damage_destroy + +end module spectral_damage diff --git a/code/spectral_thermal.f90 b/code/spectral_thermal.f90 new file mode 100644 index 000000000..fbef1c29f --- /dev/null +++ b/code/spectral_thermal.f90 @@ -0,0 +1,403 @@ +!-------------------------------------------------------------------------------------------------- +! $Id: spectral_thermal.f90 4082 2015-04-11 20:28:07Z MPIE\m.diehl $ +!-------------------------------------------------------------------------------------------------- +!> @author Pratheek Shanthraj, Max-Planck-Institut für Eisenforschung GmbH +!> @author Shaokang Zhang, Max-Planck-Institut für Eisenforschung GmbH +!> @brief Spectral solver for thermal conduction +!-------------------------------------------------------------------------------------------------- +module spectral_thermal + use prec, only: & + pInt, & + pReal + use math, only: & + math_I3 + use DAMASK_spectral_Utilities, only: & + tSolutionState, & + tSolutionParams + use numerics, only: & + worldrank, & + worldsize + + implicit none + private +#include + + character (len=*), parameter, public :: & + spectral_thermal_label = 'spectralthermal' + +!-------------------------------------------------------------------------------------------------- +! derived types + type(tSolutionParams), private :: params + +!-------------------------------------------------------------------------------------------------- +! PETSc data + SNES, private :: thermal_snes + Vec, private :: solution + PetscInt, private :: xstart, xend, ystart, yend, zstart, zend + real(pReal), private, dimension(:,:,:), allocatable :: & + temperature_current, & !< field of current temperature + temperature_lastInc, & !< field of previous temperature + temperature_stagInc !< field of staggered temperature + +!-------------------------------------------------------------------------------------------------- +! reference diffusion tensor, mobility etc. + integer(pInt), private :: totalIter = 0_pInt !< total iteration in current increment + real(pReal), dimension(3,3), private :: D_ref + real(pReal), private :: mobility_ref + character(len=1024), private :: incInfo + + public :: & + spectral_thermal_init, & + spectral_thermal_solution, & + spectral_thermal_forward, & + spectral_thermal_destroy + external :: & + VecDestroy, & + DMDestroy, & + DMDACreate3D, & + DMCreateGlobalVector, & + DMDASNESSetFunctionLocal, & + PETScFinalize, & + SNESDestroy, & + SNESGetNumberFunctionEvals, & + SNESGetIterationNumber, & + SNESSolve, & + SNESSetDM, & + SNESGetConvergedReason, & + SNESSetConvergenceTest, & + SNESSetFromOptions, & + SNESCreate, & + MPI_Abort, & + MPI_Bcast, & + MPI_Allreduce + +contains + +!-------------------------------------------------------------------------------------------------- +!> @brief allocates all neccessary fields and fills them with data, potentially from restart info +!-------------------------------------------------------------------------------------------------- +subroutine spectral_thermal_init(temperature0) + use, intrinsic :: iso_fortran_env ! to get compiler_version and compiler_options (at least for gfortran >4.6 at the moment) + use IO, only: & + IO_intOut, & + IO_read_realFile, & + IO_timeStamp + use DAMASK_spectral_Utilities, only: & + wgt + use mesh, only: & + gridLocal, & + gridGlobal + use thermal_conduction, only: & + thermal_conduction_getConductivity33, & + thermal_conduction_getMassDensity, & + thermal_conduction_getSpecificHeat + + implicit none + real(pReal), intent(inOut) :: temperature0 + integer(pInt), dimension(:), allocatable :: localK + integer(pInt) :: proc + integer(pInt) :: i, j, k, cell + DM :: thermal_grid + PetscErrorCode :: ierr + PetscObject :: dummy + + mainProcess: if (worldrank == 0_pInt) then + write(6,'(/,a)') ' <<<+- spectral_thermal init -+>>>' + write(6,'(a)') ' $Id: spectral_thermal.f90 4082 2015-04-11 20:28:07Z MPIE\m.diehl $' + write(6,'(a15,a)') ' Current time: ',IO_timeStamp() +#include "compilation_info.f90" + endif mainProcess + +!-------------------------------------------------------------------------------------------------- +! initialize solver specific parts of PETSc + call SNESCreate(PETSC_COMM_WORLD,thermal_snes,ierr); CHKERRQ(ierr) + call SNESSetOptionsPrefix(thermal_snes,'thermal_',ierr);CHKERRQ(ierr) + allocate(localK(worldsize), source = 0); localK(worldrank+1) = gridLocal(3) + do proc = 1, worldsize + call MPI_Bcast(localK(proc),1,MPI_INTEGER,proc-1,PETSC_COMM_WORLD,ierr) + enddo + call DMDACreate3d(PETSC_COMM_WORLD, & + DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, & ! cut off stencil at boundary + DMDA_STENCIL_BOX, & ! Moore (26) neighborhood around central point + gridGlobal(1),gridGlobal(2),gridGlobal(3), & ! global grid + 1, 1, worldsize, & + 1, 0, & ! #dof (temperature field), ghost boundary width (domain overlap) + gridLocal (1),gridLocal (2),localK, & ! local grid + thermal_grid,ierr) ! handle, error + CHKERRQ(ierr) + call SNESSetDM(thermal_snes,thermal_grid,ierr); CHKERRQ(ierr) ! connect snes to da + call DMCreateGlobalVector(thermal_grid,solution ,ierr); CHKERRQ(ierr) ! global solution vector (grid x 1, i.e. every def grad tensor) + call DMDASNESSetFunctionLocal(thermal_grid,INSERT_VALUES,spectral_thermal_formResidual,dummy,ierr) ! residual vector of same shape as solution vector + CHKERRQ(ierr) + call SNESSetFromOptions(thermal_snes,ierr); CHKERRQ(ierr) ! pull it all together with additional cli arguments + +!-------------------------------------------------------------------------------------------------- +! init fields + call DMDAGetCorners(thermal_grid,xstart,ystart,zstart,xend,yend,zend,ierr) + CHKERRQ(ierr) + xend = xstart + xend - 1 + yend = ystart + yend - 1 + zend = zstart + zend - 1 + call VecSet(solution,temperature0,ierr); CHKERRQ(ierr) + allocate(temperature_current(gridLocal(1),gridLocal(2),gridLocal(3)), source=temperature0) + allocate(temperature_lastInc(gridLocal(1),gridLocal(2),gridLocal(3)), source=temperature0) + allocate(temperature_stagInc(gridLocal(1),gridLocal(2),gridLocal(3)), source=temperature0) + + cell = 0_pInt + D_ref = 0.0_pReal + mobility_ref = 0.0_pReal + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,gridLocal(1) + cell = cell + 1_pInt + D_ref = D_ref + thermal_conduction_getConductivity33(1,cell) + mobility_ref = mobility_ref + thermal_conduction_getMassDensity(1,cell)* & + thermal_conduction_getSpecificHeat(1,cell) + enddo; enddo; enddo + D_ref = D_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + mobility_ref = mobility_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + +end subroutine spectral_thermal_init + +!-------------------------------------------------------------------------------------------------- +!> @brief solution for the Basic PETSC scheme with internal iterations +!-------------------------------------------------------------------------------------------------- +type(tSolutionState) function spectral_thermal_solution(guess,timeinc,timeinc_old,loadCaseTime) + use numerics, only: & + itmax, & + err_thermal_tolAbs, & + err_thermal_tolRel + use DAMASK_spectral_Utilities, only: & + tBoundaryCondition, & + Utilities_maskedCompliance, & + Utilities_updateGamma + use mesh, only: & + gridLocal + use thermal_conduction, only: & + thermal_conduction_putTemperatureAndItsRate + + implicit none + +!-------------------------------------------------------------------------------------------------- +! input data for solution + real(pReal), intent(in) :: & + timeinc, & !< increment in time for current solution + timeinc_old, & !< increment in time of last increment + loadCaseTime !< remaining time of current load case + logical, intent(in) :: guess + integer(pInt) :: i, j, k, cell + PetscInt :: position + PetscReal :: minTemperature, maxTemperature, stagNorm, solnNorm + +!-------------------------------------------------------------------------------------------------- +! PETSc Data + PetscErrorCode :: ierr + SNESConvergedReason :: reason + + spectral_thermal_solution%converged =.false. + +!-------------------------------------------------------------------------------------------------- +! set module wide availabe data + params%timeinc = timeinc + params%timeincOld = timeinc_old + + call SNESSolve(thermal_snes,PETSC_NULL_OBJECT,solution,ierr); CHKERRQ(ierr) + call SNESGetConvergedReason(thermal_snes,reason,ierr); CHKERRQ(ierr) + + if (reason < 1) then + spectral_thermal_solution%converged = .false. + spectral_thermal_solution%iterationsNeeded = itmax + else + spectral_thermal_solution%converged = .true. + spectral_thermal_solution%iterationsNeeded = totalIter + endif + stagNorm = maxval(abs(temperature_current - temperature_stagInc)) + solnNorm = maxval(abs(temperature_current)) + call MPI_Allreduce(MPI_IN_PLACE,stagNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + call MPI_Allreduce(MPI_IN_PLACE,solnNorm,1,MPI_DOUBLE,MPI_MAX,PETSC_COMM_WORLD,ierr) + temperature_stagInc = temperature_current + spectral_thermal_solution%stagConverged = stagNorm < err_thermal_tolAbs & + .or. stagNorm < err_thermal_tolRel*solnNorm + +!-------------------------------------------------------------------------------------------------- +! updating thermal state + cell = 0_pInt !< material point = 0 + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,gridLocal(1) + cell = cell + 1_pInt !< material point increase + call thermal_conduction_putTemperatureAndItsRate(temperature_current(i,j,k), & + (temperature_current(i,j,k)-temperature_lastInc(i,j,k))/params%timeinc, & + 1,cell) + enddo; enddo; enddo + + call VecMin(solution,position,minTemperature,ierr); CHKERRQ(ierr) + call VecMax(solution,position,maxTemperature,ierr); CHKERRQ(ierr) + if (worldrank == 0) then + if (spectral_thermal_solution%converged) & + write(6,'(/,a)') ' ... thermal conduction converged ..................................' + write(6,'(/,a,f8.4,2x,f8.4,2x,f8.4,/)',advance='no') ' Minimum|Maximum|Delta Temperature = ',& + minTemperature, maxTemperature, stagNorm + write(6,'(/,a)') ' ===========================================================================' + flush(6) + endif + +end function spectral_thermal_solution + + +!-------------------------------------------------------------------------------------------------- +!> @brief forms the spectral thermal residual vector +!-------------------------------------------------------------------------------------------------- +subroutine spectral_thermal_formResidual(in,x_scal,f_scal,dummy,ierr) + use mesh, only: & + gridLocal + use math, only: & + math_mul33x3 + use DAMASK_spectral_Utilities, only: & + scalarField_realMPI, & + vectorField_realMPI, & + utilities_FFTvectorForward, & + utilities_FFTvectorBackward, & + utilities_FFTscalarForward, & + utilities_FFTscalarBackward, & + utilities_fourierGreenConvolution, & + utilities_fourierScalarGradient, & + utilities_fourierVectorDivergence + use thermal_conduction, only: & + thermal_conduction_getSourceAndItsTangent, & + thermal_conduction_getConductivity33, & + thermal_conduction_getMassDensity, & + thermal_conduction_getSpecificHeat + + implicit none + DMDALocalInfo, dimension(DMDA_LOCAL_INFO_SIZE) :: & + in + PetscScalar, dimension( & + XG_RANGE,YG_RANGE,ZG_RANGE) :: & + x_scal + PetscScalar, dimension( & + X_RANGE,Y_RANGE,Z_RANGE) :: & + f_scal + PetscObject :: dummy + PetscErrorCode :: ierr + integer(pInt) :: i, j, k, cell + real(pReal) :: Tdot, dTdot_dT + + temperature_current = x_scal +!-------------------------------------------------------------------------------------------------- +! evaluate polarization field + scalarField_realMPI = 0.0_pReal + scalarField_realMPI(1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) = temperature_current + call utilities_FFTscalarForward() + call utilities_fourierScalarGradient() !< calculate gradient of damage field + call utilities_FFTvectorBackward() + cell = 0_pInt + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,gridLocal(1) + cell = cell + 1_pInt + vectorField_realMPI(1:3,i,j,k) = math_mul33x3(thermal_conduction_getConductivity33(1,cell) - D_ref, & + vectorField_realMPI(1:3,i,j,k)) + enddo; enddo; enddo + call utilities_FFTvectorForward() + call utilities_fourierVectorDivergence() !< calculate damage divergence in fourier field + call utilities_FFTscalarBackward() + cell = 0_pInt + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,gridLocal(1) + cell = cell + 1_pInt + call thermal_conduction_getSourceAndItsTangent(Tdot, dTdot_dT, temperature_current(i,j,k), 1, cell) + scalarField_realMPI(i,j,k) = params%timeinc*scalarField_realMPI(i,j,k) + & + params%timeinc*Tdot + & + thermal_conduction_getMassDensity (1,cell)* & + thermal_conduction_getSpecificHeat(1,cell)*(temperature_lastInc(i,j,k) - & + temperature_current(i,j,k)) + & + mobility_ref*temperature_current(i,j,k) + enddo; enddo; enddo + +!-------------------------------------------------------------------------------------------------- +! convolution of damage field with green operator + call utilities_FFTscalarForward() + call utilities_fourierGreenConvolution(D_ref, mobility_ref, params%timeinc) + call utilities_FFTscalarBackward() + +!-------------------------------------------------------------------------------------------------- +! constructing residual + f_scal = temperature_current - scalarField_realMPI(1:gridLocal(1),1:gridLocal(2),1:gridLocal(3)) + +end subroutine spectral_thermal_formResidual + +!-------------------------------------------------------------------------------------------------- +!> @brief forwarding routine +!-------------------------------------------------------------------------------------------------- +subroutine spectral_thermal_forward(guess,timeinc,timeinc_old,loadCaseTime) + use mesh, only: & + gridLocal + use DAMASK_spectral_Utilities, only: & + cutBack, & + wgt + use thermal_conduction, only: & + thermal_conduction_putTemperatureAndItsRate, & + thermal_conduction_getConductivity33, & + thermal_conduction_getMassDensity, & + thermal_conduction_getSpecificHeat + + implicit none + real(pReal), intent(in) :: & + timeinc_old, & + timeinc, & + loadCaseTime !< remaining time of current load case + logical, intent(in) :: guess + integer(pInt) :: i, j, k, cell + DM :: dm_local + PetscScalar, pointer :: x_scal(:,:,:) + PetscErrorCode :: ierr + + if (cutBack) then + temperature_current = temperature_lastInc + temperature_stagInc = temperature_lastInc + +!-------------------------------------------------------------------------------------------------- +! reverting thermal field state + cell = 0_pInt !< material point = 0 + call SNESGetDM(thermal_snes,dm_local,ierr); CHKERRQ(ierr) + call DMDAVecGetArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) !< get the data out of PETSc to work with + x_scal(xstart:xend,ystart:yend,zstart:zend) = temperature_current + call DMDAVecRestoreArrayF90(dm_local,solution,x_scal,ierr); CHKERRQ(ierr) + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,gridLocal(1) + cell = cell + 1_pInt !< material point increase + call thermal_conduction_putTemperatureAndItsRate(temperature_current(i,j,k), & + (temperature_current(i,j,k) - & + temperature_lastInc(i,j,k))/params%timeinc, & + 1,cell) + enddo; enddo; enddo + else +!-------------------------------------------------------------------------------------------------- +! update rate and forward last inc + temperature_lastInc = temperature_current + cell = 0_pInt + D_ref = 0.0_pReal + mobility_ref = 0.0_pReal + do k = 1_pInt, gridLocal(3); do j = 1_pInt, gridLocal(2); do i = 1_pInt,gridLocal(1) + cell = cell + 1_pInt + D_ref = D_ref + thermal_conduction_getConductivity33(1,cell) + mobility_ref = mobility_ref + thermal_conduction_getMassDensity(1,cell)* & + thermal_conduction_getSpecificHeat(1,cell) + enddo; enddo; enddo + D_ref = D_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,D_ref,9,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + mobility_ref = mobility_ref*wgt + call MPI_Allreduce(MPI_IN_PLACE,mobility_ref,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD,ierr) + endif + + end subroutine spectral_thermal_forward + +!-------------------------------------------------------------------------------------------------- +!> @brief destroy routine +!-------------------------------------------------------------------------------------------------- +subroutine spectral_thermal_destroy() + + implicit none + PetscErrorCode :: ierr + + call VecDestroy(solution,ierr); CHKERRQ(ierr) + call SNESDestroy(thermal_snes,ierr); CHKERRQ(ierr) + +end subroutine spectral_thermal_destroy + +end module spectral_thermal