!-------------------------------------------------------------------------------------------------- !> @author Franz Roters, Max-Planck-Institut für Eisenforschung GmbH !> @author Philip Eisenlohr, Max-Planck-Institut für Eisenforschung GmbH !> @brief elasticity, plasticity, damage & thermal internal microstructure state !-------------------------------------------------------------------------------------------------- module phase use prec use constants use math use rotations use polynomials use tables use IO use config use material use result use crystal use discretization use parallelization use HDF5 use HDF5_utilities implicit none(type,external) private type :: tState integer :: & sizeState = 0, & !< size of state sizeDotState = 0, & !< size of dot state, i.e. state(1:sizeDot) follows time evolution by dotState rates offsetDeltaState = 0, & !< index offset of delta state sizeDeltaState = 0 !< size of delta state, i.e. state(offset+1:offset+sizeDelta) follows time evolution by deltaState increments real(pREAL), allocatable, dimension(:) :: & atol ! http://stackoverflow.com/questions/3948210 real(pREAL), pointer, dimension(:,:), contiguous :: & !< is basically an allocatable+target, but in a type needs to be pointer state0, & state, & !< state dotState, & !< rate of state change deltaState !< increment of state change real(pREAL), pointer, dimension(:,:) :: & deltaState2 end type type, extends(tState) :: tPlasticState logical :: nonlocal = .false. end type type :: tSourceState type(tState), dimension(:), allocatable :: p !< tState for each active source mechanism in a phase end type enum, bind(c); enumerator :: & UNDEFINED, & MECHANICAL_PLASTICITY_NONE, & MECHANICAL_PLASTICITY_ISOTROPIC, & MECHANICAL_PLASTICITY_PHENOPOWERLAW, & MECHANICAL_PLASTICITY_KINEHARDENING, & MECHANICAL_PLASTICITY_DISLOTWIN, & MECHANICAL_PLASTICITY_DISLOTUNGSTEN, & MECHANICAL_PLASTICITY_NONLOCAL, & MECHANICAL_EIGEN_THERMALEXPANSION, & DAMAGE_ISOBRITTLE, & DAMAGE_ANISOBRITTLE, & THERMAL_SOURCE_DISSIPATION, & THERMAL_SOURCE_EXTERNALHEAT end enum integer(kind(UNDEFINED)), dimension(:), allocatable :: & mechanical_plasticity_type, & !< plasticity of each phase damage_type !< damage type of each phase integer(kind(UNDEFINED)), dimension(:,:), allocatable :: & thermal_source_type, & mechanical_eigen_kinematics_type character(len=2), allocatable, dimension(:) :: phase_lattice real(pREAL), allocatable, dimension(:) :: phase_cOverA real(pREAL), allocatable, dimension(:) :: phase_rho type(tRotationContainer), dimension(:), allocatable :: & phase_O_0, & phase_O type :: tNumerics integer :: & iJacoLpresiduum, & !< frequency of Jacobian update of residuum in Lp iJacoLiresiduum, & !< frequency of Jacobian update of residuum in Li nState, & !< state loop limit nStress_Lp, & !< stress loop limit for Lp nStress_Li !< stress loop limit for Li real(pREAL) :: & stepMinCryst, & !< minimum (relative) size of sub-step allowed during cutback stepSizeCryst, & !< size of first substep when cutback stepSizeLp, & !< size of first substep when cutback in Lp calculation stepSizeLi, & !< size of first substep when cutback in Li calculation stepIncreaseCryst, & !< increase of next substep size when previous substep converged rtol_crystalliteState, & rtol_Lp, & !< relative tolerance in stress loop for Lp atol_Lp, & !< absolute tolerance in stress loop for Lp rtol_Li, & !< relative tolerance in stress loop for Li atol_Li !< absolute tolerance in stress loop for Li end type tNumerics type(tNumerics) :: num ! numerics parameters. Better name? type(tPlasticState), allocatable, dimension(:), public :: & plasticState type(tState), allocatable, dimension(:), public :: & damageState interface ! == cleaned:begin ================================================================================= module subroutine mechanical_init(phases,num_mech) type(tDict), pointer :: phases, num_mech end subroutine mechanical_init module subroutine damage_init end subroutine damage_init module subroutine thermal_init(phases) type(tDict), pointer :: phases end subroutine thermal_init module subroutine mechanical_result(group,ph) character(len=*), intent(in) :: group integer, intent(in) :: ph end subroutine mechanical_result module subroutine damage_result(group,ph) character(len=*), intent(in) :: group integer, intent(in) :: ph end subroutine damage_result module subroutine thermal_result(group,ph) character(len=*), intent(in) :: group integer, intent(in) :: ph end subroutine thermal_result module subroutine mechanical_forward() end subroutine mechanical_forward module subroutine damage_forward() end subroutine damage_forward module subroutine thermal_forward() end subroutine thermal_forward module subroutine mechanical_restore(ce,includeL) integer, intent(in) :: ce logical, intent(in) :: includeL end subroutine mechanical_restore module subroutine damage_restore(ce) integer, intent(in) :: ce end subroutine damage_restore module function phase_mechanical_dPdF(Delta_t,co,ce) result(dPdF) real(pREAL), intent(in) :: Delta_t integer, intent(in) :: & co, & !< counter in constituent loop ce real(pREAL), dimension(3,3,3,3) :: dPdF end function phase_mechanical_dPdF module subroutine mechanical_restartWrite(groupHandle,ph) integer(HID_T), intent(in) :: groupHandle integer, intent(in) :: ph end subroutine mechanical_restartWrite module subroutine thermal_restartWrite(groupHandle,ph) integer(HID_T), intent(in) :: groupHandle integer, intent(in) :: ph end subroutine thermal_restartWrite module subroutine damage_restartWrite(groupHandle,ph) integer(HID_T), intent(in) :: groupHandle integer, intent(in) :: ph end subroutine damage_restartWrite module subroutine mechanical_restartRead(groupHandle,ph) integer(HID_T), intent(in) :: groupHandle integer, intent(in) :: ph end subroutine mechanical_restartRead module subroutine thermal_restartRead(groupHandle,ph) integer(HID_T), intent(in) :: groupHandle integer, intent(in) :: ph end subroutine thermal_restartRead module subroutine damage_restartRead(groupHandle,ph) integer(HID_T), intent(in) :: groupHandle integer, intent(in) :: ph end subroutine damage_restartRead module function mechanical_S(ph,en) result(S) integer, intent(in) :: ph,en real(pREAL), dimension(3,3) :: S end function mechanical_S module function mechanical_L_p(ph,en) result(L_p) integer, intent(in) :: ph,en real(pREAL), dimension(3,3) :: L_p end function mechanical_L_p module function mechanical_F_e(ph,en) result(F_e) integer, intent(in) :: ph,en real(pREAL), dimension(3,3) :: F_e end function mechanical_F_e module function mechanical_F_i(ph,en) result(F_i) integer, intent(in) :: ph,en real(pREAL), dimension(3,3) :: F_i end function mechanical_F_i module function phase_F(co,ce) result(F) integer, intent(in) :: co, ce real(pREAL), dimension(3,3) :: F end function phase_F module function phase_P(co,ce) result(P) integer, intent(in) :: co, ce real(pREAL), dimension(3,3) :: P end function phase_P pure module function thermal_T(ph,en) result(T) integer, intent(in) :: ph,en real(pREAL) :: T end function thermal_T module function thermal_dot_T(ph,en) result(dot_T) integer, intent(in) :: ph,en real(pREAL) :: dot_T end function thermal_dot_T module function damage_phi(ph,en) result(phi) integer, intent(in) :: ph,en real(pREAL) :: phi end function damage_phi module subroutine phase_set_F(F,co,ce) real(pREAL), dimension(3,3), intent(in) :: F integer, intent(in) :: co, ce end subroutine phase_set_F module subroutine phase_thermal_setField(T,dot_T, co,ce) real(pREAL), intent(in) :: T, dot_T integer, intent(in) :: co, ce end subroutine phase_thermal_setField module subroutine phase_set_phi(phi,co,ce) real(pREAL), intent(in) :: phi integer, intent(in) :: co, ce end subroutine phase_set_phi module function phase_mu_phi(co,ce) result(mu) integer, intent(in) :: co, ce real(pREAL) :: mu end function phase_mu_phi module function phase_K_phi(co,ce) result(K) integer, intent(in) :: co, ce real(pREAL), dimension(3,3) :: K end function phase_K_phi module function phase_mu_T(co,ce) result(mu) integer, intent(in) :: co, ce real(pREAL) :: mu end function phase_mu_T module function phase_K_T(co,ce) result(K) integer, intent(in) :: co, ce real(pREAL), dimension(3,3) :: K end function phase_K_T ! == cleaned:end =================================================================================== module function phase_thermal_constitutive(Delta_t,ph,en) result(status) real(pREAL), intent(in) :: Delta_t integer, intent(in) :: ph, en integer(kind(STATUS_OK)) :: status end function phase_thermal_constitutive module function phase_damage_constitutive(Delta_t,co,ce) result(status) real(pREAL), intent(in) :: Delta_t integer, intent(in) :: co, ce integer(kind(STATUS_OK)) :: status end function phase_damage_constitutive module function phase_mechanical_constitutive(Delta_t,co,ce) result(status) real(pREAL), intent(in) :: Delta_t integer, intent(in) :: co, ce integer(kind(STATUS_OK)) :: status end function phase_mechanical_constitutive !ToDo: Merge all the stiffness functions module function phase_homogenizedC66(ph,en) result(C) integer, intent(in) :: ph, en real(pREAL), dimension(6,6) :: C end function phase_homogenizedC66 module function phase_damage_C66(C66,ph,en) result(C66_degraded) real(pREAL), dimension(6,6), intent(in) :: C66 integer, intent(in) :: ph,en real(pREAL), dimension(6,6) :: C66_degraded end function phase_damage_C66 module function phase_f_phi(phi,co,ce) result(f) integer, intent(in) :: ce,co real(pREAL), intent(in) :: & phi !< damage parameter real(pREAL) :: & f end function phase_f_phi module function phase_f_T(ph,en) result(f) integer, intent(in) :: ph, en real(pREAL) :: f end function phase_f_T module subroutine plastic_dependentState(ph,en) integer, intent(in) :: & ph, & en end subroutine plastic_dependentState module subroutine damage_anisobrittle_LiAndItsTangent(L_i, dL_i_dM_i, M_i, ph,en) integer, intent(in) :: ph, en real(pREAL), intent(in), dimension(3,3) :: & M_i real(pREAL), intent(out), dimension(3,3) :: & L_i !< damage velocity gradient real(pREAL), intent(out), dimension(3,3,3,3) :: & dL_i_dM_i !< derivative of L_i with respect to M_i end subroutine damage_anisobrittle_LiAndItsTangent end interface public :: & phase_init, & phase_homogenizedC66, & phase_f_phi, & phase_f_T, & phase_K_phi, & phase_K_T, & phase_mu_phi, & phase_mu_T, & phase_result, & phase_allocateState, & phase_forward, & phase_restore, & converged, & phase_mechanical_constitutive, & phase_thermal_constitutive, & phase_damage_constitutive, & phase_mechanical_dPdF, & crystallite_orientations, & crystallite_push33ToRef, & phase_restartWrite, & phase_restartRead, & phase_thermal_setField, & phase_set_phi, & phase_P, & phase_set_F, & phase_F contains !-------------------------------------------------------------------------------------------------- !> @brief Initialize constitutive models for individual physics !-------------------------------------------------------------------------------------------------- subroutine phase_init() integer :: & ph, ce, co, ma type(tDict), pointer :: & phases, & phase, & num_phase, & num_mech character(len=:), allocatable :: refs print'(/,1x,a)', '<<<+- phase init -+>>>'; flush(IO_STDOUT) phases => config_material%get_dict('phase') allocate(phase_lattice(phases%length)) allocate(phase_cOverA(phases%length),source=-1.0_pREAL) allocate(phase_rho(phases%length)) allocate(phase_O_0(phases%length)) do ph = 1,phases%length print'(/,1x,a,i0,a)', 'phase ',ph,': '//phases%key(ph) phase => phases%get_dict(ph) refs = config_listReferences(phase,indent=3) if (len(refs) > 0) print'(/,1x,a)', refs phase_rho(ph) = phase%get_asReal('rho',defaultVal=0.0_pREAL) phase_lattice(ph) = phase%get_asStr('lattice') if (all(phase_lattice(ph) /= ['cF','cI','hP','tI'])) & call IO_error(130,ext_msg='phase_init: '//phase%get_asStr('lattice')) if (any(phase_lattice(ph) == ['hP','tI'])) & phase_cOverA(ph) = phase%get_asReal('c/a') allocate(phase_O_0(ph)%data(count(material_ID_phase==ph))) end do do ce = 1, size(material_ID_phase,2) ma = discretization_materialAt((ce-1)/discretization_nIPs+1) do co = 1,homogenization_Nconstituents(material_ID_homogenization(ce)) ph = material_ID_phase(co,ce) phase_O_0(ph)%data(material_entry_phase(co,ce)) = material_O_0(ma)%data(co) end do end do allocate(phase_O(phases%length)) do ph = 1,phases%length phase_O(ph)%data = phase_O_0(ph)%data end do num_phase => config_numerics%get_dict('phase',defaultVal=emptyDict) num_mech => num_phase%get_dict('mechanical', defaultVal=emptyDict) call mechanical_init(phases,num_mech) call damage_init() call thermal_init(phases) call crystallite_init() end subroutine phase_init !-------------------------------------------------------------------------------------------------- !> @brief Allocate the components of the state structure for a given phase !-------------------------------------------------------------------------------------------------- subroutine phase_allocateState(state, & NEntries,sizeState,sizeDotState,sizeDeltaState,offsetDeltaState) class(tState), intent(inout) :: & state integer, intent(in) :: & NEntries, & sizeState, & sizeDotState, & sizeDeltaState integer, intent(in), optional :: & offsetDeltaState state%sizeState = sizeState state%sizeDotState = sizeDotState state%sizeDeltaState = sizeDeltaState if (present(offsetDeltaState)) then state%offsetDeltaState = offsetDeltaState ! ToDo: this is a fix for broken nonlocal else state%offsetDeltaState = sizeState-sizeDeltaState ! deltaState occupies latter part of state by definition end if allocate(state%atol (sizeState), source=0.0_pREAL) allocate(state%state0 (sizeState,NEntries), source=0.0_pREAL) allocate(state%state (sizeState,NEntries), source=0.0_pREAL) allocate(state%dotState (sizeDotState,NEntries), source=0.0_pREAL) allocate(state%deltaState (sizeDeltaState,NEntries), source=0.0_pREAL) state%deltaState2 => state%state(state%offsetDeltaState+1: & state%offsetDeltaState+state%sizeDeltaState,:) end subroutine phase_allocateState !-------------------------------------------------------------------------------------------------- !> @brief Restore data after homog cutback. !-------------------------------------------------------------------------------------------------- subroutine phase_restore(ce,includeL) logical, intent(in) :: includeL integer, intent(in) :: ce call mechanical_restore(ce,includeL) call damage_restore(ce) end subroutine phase_restore !-------------------------------------------------------------------------------------------------- !> @brief Forward data after successful increment. !-------------------------------------------------------------------------------------------------- subroutine phase_forward() call mechanical_forward() call damage_forward() call thermal_forward() end subroutine phase_forward !-------------------------------------------------------------------------------------------------- !> @brief writes constitutive results to HDF5 output file !-------------------------------------------------------------------------------------------------- subroutine phase_result() integer :: ph character(len=:), allocatable :: group call result_closeGroup(result_addGroup('/current/phase/')) do ph = 1, size(material_name_phase) group = '/current/phase/'//trim(material_name_phase(ph))//'/' call result_closeGroup(result_addGroup(group)) call mechanical_result(group,ph) call damage_result(group,ph) call thermal_result(group,ph) end do end subroutine phase_result !-------------------------------------------------------------------------------------------------- !> @brief Allocate and initialize. !-------------------------------------------------------------------------------------------------- subroutine crystallite_init() integer :: & ce, & co, & !< counter in integration point component loop en, ph !$OMP PARALLEL DO PRIVATE(ph,en) do ce = 1, size(material_ID_homogenization) do co = 1,homogenization_Nconstituents(material_ID_homogenization(ce)) ph = material_ID_phase(co,ce) en = material_entry_phase(co,ce) call crystallite_orientations(co,ce) call plastic_dependentState(ph,en) ! update dependent state variables to be consistent with basic states end do end do !$OMP END PARALLEL DO end subroutine crystallite_init !-------------------------------------------------------------------------------------------------- !> @brief Update orientations and, if needed, compatibility. !-------------------------------------------------------------------------------------------------- subroutine crystallite_orientations(co,ce) integer, intent(in) :: & co, & ce integer :: ph, en ph = material_ID_phase(co,ce) en = material_entry_phase(co,ce) call phase_O(ph)%data(en)%fromMatrix(transpose(math_rotationalPart(mechanical_F_e(ph,en)))) end subroutine crystallite_orientations !-------------------------------------------------------------------------------------------------- !> @brief Map 2nd order tensor to reference configuration. !-------------------------------------------------------------------------------------------------- function crystallite_push33ToRef(co,ce, tensor33) real(pREAL), dimension(3,3), intent(in) :: tensor33 integer, intent(in):: & co, & ce real(pREAL), dimension(3,3) :: crystallite_push33ToRef real(pREAL), dimension(3,3) :: T integer :: ph, en ph = material_ID_phase(co,ce) en = material_entry_phase(co,ce) T = matmul(phase_O_0(ph)%data(en)%asMatrix(),transpose(math_inv33(phase_F(co,ce)))) ! ToDo: initial orientation correct? crystallite_push33ToRef = matmul(transpose(T),matmul(tensor33,T)) end function crystallite_push33ToRef !-------------------------------------------------------------------------------------------------- !> @brief Determine whether a point is converged. !-------------------------------------------------------------------------------------------------- logical pure function converged(residuum,state,atol) real(pREAL), intent(in), dimension(:) :: & residuum, state, atol real(pREAL) :: & rTol rTol = num%rTol_crystalliteState converged = all(abs(residuum) <= max(atol, rtol*abs(state))) end function converged !-------------------------------------------------------------------------------------------------- !> @brief Write restart data to file. !-------------------------------------------------------------------------------------------------- subroutine phase_restartWrite(fileHandle) integer(HID_T), intent(in) :: fileHandle integer(HID_T), dimension(2) :: groupHandle integer :: ph groupHandle(1) = HDF5_addGroup(fileHandle,'phase') do ph = 1, size(material_name_phase) groupHandle(2) = HDF5_addGroup(groupHandle(1),material_name_phase(ph)) call mechanical_restartWrite(groupHandle(2),ph) call thermal_restartWrite(groupHandle(2),ph) call damage_restartWrite(groupHandle(2),ph) call HDF5_closeGroup(groupHandle(2)) end do call HDF5_closeGroup(groupHandle(1)) end subroutine phase_restartWrite !-------------------------------------------------------------------------------------------------- !> @brief Read restart data from file. !-------------------------------------------------------------------------------------------------- subroutine phase_restartRead(fileHandle) integer(HID_T), intent(in) :: fileHandle integer(HID_T), dimension(2) :: groupHandle integer :: ph groupHandle(1) = HDF5_openGroup(fileHandle,'phase') do ph = 1, size(material_name_phase) groupHandle(2) = HDF5_openGroup(groupHandle(1),material_name_phase(ph)) call mechanical_restartRead(groupHandle(2),ph) call thermal_restartRead(groupHandle(2),ph) call damage_restartRead(groupHandle(2),ph) call HDF5_closeGroup(groupHandle(2)) end do call HDF5_closeGroup(groupHandle(1)) end subroutine phase_restartRead end module phase