0% found this document useful (0 votes)
20 views29 pages

Mod SLD Stress Model 155

This document describes a Fortran implementation of a material model for resins based on António Melro's work, adapted for Alya. It outlines the material properties, state variables, and damage laws used in the model, as well as the structure of the UMAT subroutine for stress calculations. The document also notes discrepancies with equations in the original paper and provides details on the initialization and iterative processes for calculating stress and damage parameters.

Uploaded by

fateto2143
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views29 pages

Mod SLD Stress Model 155

This document describes a Fortran implementation of a material model for resins based on António Melro's work, adapted for Alya. It outlines the material properties, state variables, and damage laws used in the model, as well as the structure of the UMAT subroutine for stress calculations. The document also notes discrepancies with equations in the original paper and provides details on the initialization and iterative processes for calculating stress and damage parameters.

Uploaded by

fateto2143
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 29

!

===================================================================================
=======
! This UMAT implements the model of António Melro for resins, using Fortran
Modern
! language.
!
! ! Adaptated version for Alya from Igors's remanufacturings
!
!
===================================================================================
=======
!
! PROPS (7)
! PROPS(1) --> YOUNG MODULUS ----------------------> EYOUNG
! PROPS(2) --> POISSON COEFFICIENT ----------------> ENIU
! PROPS(3) --> COEFFICIENT OF THERMAL EXPANSION ---> ALPHA
! PROPS(4) --> PLASTIC POISSON COEFFICIENT --------> PNIU
! PROPS(5) --> TENSION FAILURE STRESS -------------> XT
! PROPS(6) --> COMPRESSION FAILURE STRESS ---------> XC
! PROPS(7) --> FRACTURE TOUGHNESS -----------------> GCM
!
===================================================================================
=======
!
! STATE VARIABLES (10)
! STATEV(1) ----> INTERNAL VARIABLE ---------------> RINT
! STATEV(2) ----> DAMAGE PARAMETER ----------------> eps_f
! STATEV(3) ----> DAMAGE VARIABLE -----------------> DAMAGE
! STATEV(4) ----> EQUIVALENT PLASTIC STRAIN -------> EQPLAS
! STATEV(5) ----> PLASTIC EPSILON_11 --------------> EPLAST(1)
! STATEV(6) ----> PLASTIC EPSILON_22 --------------> EPLAST(2)
! STATEV(7) ----> PLASTIC EPSILON_33 --------------> EPLAST(3)
! STATEV(8) ----> PLASTIC GAMA_12 -----------------> EPLAST(4)
! STATEV(9) ----> PLASTIC GAMA_13 -----------------> EPLAST(5)
! STATEV(10) ---> PLASTIC GAMA_23 -----------------> EPLAST(6)
!
! STATEV(11) ---> STRESS S11 -----------------> S(1)
! STATEV(12) ---> STRESS S22 -----------------> S(2)
! STATEV(13) ---> STRESS S33 -----------------> S(3)
! STATEV(14) ---> STRESS S12 -----------------> S(4)
! STATEV(15) ---> STRESS S13 -----------------> S(5)
! STATEV(16) ---> STRESS S23 -----------------> S(6)

! STATEV(17) ---> STRAN-DSTRAN -----------------> S(1)


! STATEV(18) ---> STRAN-DSTRAN -----------------> S(2)
! STATEV(19) ---> STRAN-DSTRAN -----------------> S(3)
! STATEV(20) ---> STRAN-DSTRAN -----------------> S(4)
! STATEV(21) ---> STRAN-DSTRAN -----------------> S(5)
! STATEV(22) ---> STRAN-DSTRAN -----------------> S(6)
!
!
! Three damage laws are investigated:
!
! - UMAT_Matrix_Melro_Arefi
! - UMAT_Matrix_Melro_ClassicalDamage
! - UMAT_Matrix_Melro_DamageExponential
!
!
===================================================================================
=======
! Arguments
!
===================================================================================
=======
!
! Typos in the paper.
!
!Eq. 32 is different with respect to the paper.
!Eq. 34 calculation of psi value, zeta_s is at power 2 while at the paper no.

module mod_sld_stress_model_155

use def_kintyp, only : ip, rp, lg


use def_master, only : dtime, itinn, ittim, modul

implicit none

integer(ip), parameter :: SM155_AREFI_VERSION = 1_ip


integer(ip), parameter :: SM155_CLASSICAL_VERSION = 2_ip
integer(ip), parameter :: SM155_EXPONENTIAL_VERSION = 3_ip

public :: sld_stress_model_155

contains

subroutine umat(STRESS, STATEV, DDSDDE, &


STRAN, DSTRAN, NDI, NSHR, NTENS, &
NSTATV, lawco, PROPS, NPROPS, &
CELENT)

implicit none

integer(ip), intent(in) :: ntens ! Number of stress components


integer(ip), intent(in) :: nprops ! Number of user-defined materials
properties
integer(ip), intent(in) :: nstatv ! Number of user-defined state variables
(defined by *DEPVAR)
integer(ip), intent(in) :: nshr
integer(ip), intent(in) :: ndi
integer(ip), intent(in) :: lawco

real(rp), intent(inout) :: stress(ntens) ! Stress tensor at


the beggining (in) and end (out) of the increment.
real(rp), intent(inout) :: statev(nstatv)
real(rp), intent(out) :: ddsdde(ntens,ntens) ! Tangent matrix
real(rp), intent(in) :: stran(ntens) ! Total strain
tensor
real(rp), intent(in) :: dstran(ntens) ! Increment strain
tensor
real(rp), intent(in) :: props(nprops) ! Material
properties
real(rp), intent(in) :: celent ! Characteristic
element length
!
!
===================================================================================
=======
! ! Local variables
!
===================================================================================
=======
!
real(rp) :: E, nu, nu_p, Gc, G_shear, K_bulk, alpha_p, alpha, XT, XC !
Material properties
real(rp) :: syt, syc, hc, ht
real(rp) :: epbar, epbar_old ! Current yield stresses (tension and
compression), and their derivatives
real(rp) :: damage ! Accumulated plastic strain
real(rp) :: dstress(ntens), sdev_trial(ntens), dstrain_p(ntens), I2(ntens)
! Damage variable
real(rp) :: I4(ntens,ntens), IoI(ntens,ntens), SoI(ntens,ntens),
IoS(ntens,ntens), SoS(ntens,ntens) ! 2nd-order tensors
real(rp) :: I1_trial, J2_trial
! 4th-order tensors stored in matrix format
real(rp) :: dgamma, zeta_p, zeta_s, eta, beta, phi, psi, rho, chi, A !
Stress invariants
real(rp) :: y_func, depb_ddgamma, dres_dgamma, ddgamma, res
real(rp) :: dsigc_ddgamma, dsigt_ddgamma
real(rp) :: stran_e(ntens), stress_eff(ntens), sdev_eff(ntens)
real(rp) :: J2_eff, I1_eff
real(rp) :: rint, f_fail, load_func
real(rp) :: Celastic(ntens,ntens), Cdamaged(ntens,ntens)
real(rp) :: eta_visco, damage_old
integer(ip) :: iiter, i, j, itens ! Other real values

!
! User parameters
!
real(rp), parameter :: tol_conv = 1.0e-6_rp !< Convergence tolerance of
th NR
integer(ip), parameter :: miter = 100_ip !< Maximum number of NR
iterations

! Read material properties from props vector


E = props(1)
nu = props(2)
alpha = props(3) ! not used
nu_p = props(4)
XT = props(5)
XC = props(6)
Gc = props(7)
eta = props(8)
! Compute other parameters
G_shear = E / 2.0_rp / (1.0_rp + nu) !
Shear modulus
K_bulk = E / 3.0_rp / (1.0_rp - 2.0_rp*nu) !
Bulk modulus
alpha_p = (9.0_rp / 2.0_rp) * (1.0_rp - 2.0_rp * nu_p) / (1.0_rp + nu_p) ! Eq.
13
!
! Check element size
!
if( celent > 2.0_rp*Gc*E/XT**2.0_rp ) then ! BSC
print*,celent,2.0_rp*Gc*E/XT**2.0_rp
call runend('MESH IS TOOOOOO COARSE')
end if
!
! Initializations: damage, accumulated plastic strain, and plastic strains
vector
!
rint = statev(1)
damage = statev(3)
epbar = statev(4)
epbar_old = epbar
dgamma = 0.0_rp
!
! If not done yet, initialise the damage parameter Am (or eps_f)
if( lawco == SM155_AREFI_VERSION ) then
!if( statev(2) < 0.0_rp ) then ! eps_f < 0 ! ABAQUS
if( ittim == 1_ip ) then ! BSC
rint = 1.0_rp
statev(1) = rint
statev(2) = 2.0_rp * Gc / celent / XT
statev(3:nstatv) = 0.0_rp
end if
else if( lawco == SM155_CLASSICAL_VERSION ) then
if( ittim == 1_ip ) then ! BSC
rint = 1.0_rp
statev(1) = rint
call GetDamageParameterAClassical(statev(2), E, XT, XC, Gc, celent)
statev(3:nstatv) = 0.0_rp
end if
else if( lawco == SM155_EXPONENTIAL_VERSION ) then
!if( statev(2) < 0.0_rp ) then ! eps_f < 0 ! ABAQUS
if( ittim == 1_ip ) then ! BSC
rint = 1.0_rp
statev(1) = rint
call GetDamageParameterAExponential(statev(2), E, nu, XT, XC, Gc, celent)
statev(3:nstatv) = 0.0_rp
end if
end if
!
! Elastic matrix - undamaged (with damage = 0.0 in the argument)
!
call DamagedElasticMatrix(ndi, nshr, E, nu, G_shear, 0.0_rp, Celastic)

ddsdde = 0.0_rp ! BSC


if( damage <= 0.0_rp ) then
!
! Elastic predictor: Compute elastic trial state
=========================================
!
! Trial elastic step
ddsdde = Celastic
dstress = matmul(ddsdde, dstran)
stress = stress + dstress

! Evaluate yield function: Yield stress and yield surface (elastic or not)
call yielcurv( 1, epbar, syt, ht)
call yielcurv(-1, epbar, syc, hc)

! Compute trial effective stress and uniaxial yield stress


I1_trial = stress(1) + stress(2) + stress(3)
J2_trial = ((stress(1) - stress(2))**2.0_rp + (stress(3) -
stress(2))**2.0_rp + &
(stress(3) - stress(1))**2.0_rp) / 6.0_rp
do itens = ndi+1,ntens
J2_trial = J2_trial + stress(itens)**2.0_rp
end do

! Yield function value (trial state)


y_func = 6.0_rp * J2_trial + 2.0_rp * (syc - syt) * I1_trial - 2.0_rp * syt
* syc

! Check for plastic admissibility


if( y_func / (2.0_rp * syt * syc) < tol_conv ) then
! it is an elastic increment
go to 100
end if

!
===================================================================================
======
! Plastic increment - go for return mapping
!
! Initialise some needed parameters
!
zeta_s = 1.0_rp + 6.0_rp * G_shear * dgamma
! Eq. 25
zeta_p = 1.0_rp + 2.0_rp * K_bulk * alpha_p * dgamma
! Eq. 25
A = 18.0_rp * J2_trial / zeta_s**2.0_rp + 4.0_rp / 27.0_rp * (alpha_p *
I1_trial / zeta_p)**2.0_rp ! Eq. 28
res = y_func
!
! Newton-Raphson iterative cycle
!
do iiter = 1,miter

! Derivative of the accumulated plastic strain with respect to the


plastic multiplier
depb_ddgamma = sqrt(A) - dgamma / 2.0_rp / sqrt(A) * (216.0_rp * G_shear
* J2_trial / zeta_s**3.0_rp + & ! Eq. 32
16.0_rp * (alpha_p**3.0_rp) * K_bulk * I1_trial**2.0_rp / 27.0_rp /
zeta_p**3.0_rp)
depb_ddgamma = sqrt(1.0_rp / (1.0_rp + 2.0_rp * nu_p**2.0_rp) ) *
depb_ddgamma ! Eq. 32

! Derivative of residual with respect to the plastic multiplier


dsigc_ddgamma = hc * depb_ddgamma
! Eq. 30
dsigt_ddgamma = ht * depb_ddgamma
! Eq. 31
dres_dgamma = 2.0_rp * I1_trial/zeta_p * (dsigc_ddgamma - dsigt_ddgamma)
- & ! Eq. 29
4.0_rp * K_bulk * alpha_p * I1_trial * (syc - syt) / zeta_p**2.0_rp
- &
72.0_rp * G_shear * J2_trial/zeta_s**3.0_rp - 2.0_rp * depb_ddgamma
* (syc * ht + syt * hc)

! Increment of plastic multiplier


ddgamma = - res / dres_dgamma
dgamma = dgamma + ddgamma

! Re-compute the parameters needed to update the residual value


zeta_s = 1.0_rp + 6.0_rp * G_shear * dgamma
! Eq. 25
zeta_p = 1.0_rp + 2.0_rp * K_bulk * alpha_p * dgamma
! Eq. 25
A = 18.0_rp * J2_trial / zeta_s**2.0_rp + 4.0_rp / 27.0_rp * (alpha_p *
I1_trial / zeta_p)**2.0_rp ! Eq. 28
epbar = epbar_old + dgamma * sqrt(A / (1.0_rp + 2.0_rp * nu_p**2.0_rp))
! Eq. 28

! Get hardening slopes


call yielcurv( 1, epbar, syt, ht)
call yielcurv(-1, epbar, syc, hc)

res = 6.0_rp * J2_trial / zeta_s**2.0_rp + 2.0_rp * (syc - syt) *


I1_trial / zeta_p - 2.0_rp * syc * syt ! Eq. 26

! Check convergence
if( abs(res/(2.0_rp * syt * syc)) < tol_conv ) then ! Converged

! Compute the updated stress tensor


sdev_trial = stress
do i = 1,ndi
sdev_trial(i) = sdev_trial(i) - I1_trial / 3.0_rp
end do
! Updated stress tensor
stress = sdev_trial/zeta_s
do i = 1,ndi
stress(i) = stress(i) + I1_trial / (3.0_rp * zeta_p)
end do
!
! Save also the plastic strains
statev(4) = epbar
do i = 1,ndi
dstrain_p(i) = 3.0_rp * sdev_trial(i)/zeta_s + 2.0_rp * I1_trial *
alpha_p / zeta_p / 9.0_rp
end do
do i = ndi+1,ntens
dstrain_p(i) = 6.0_rp * sdev_trial(i) / zeta_s
end do
dstrain_p = dstrain_p * dgamma ! Plastic strain
statev(5:4+ntens) = statev(5:4+ntens) + dstrain_p
go to 100
end if
end do

if( iiter == miter ) then


print*,'NR iterations did not converge. res=',abs(res/(2.0_rp*syt*syc))
call runend('SM155: Maximum iteration reached!')
end if

end if

100 continue
!
===================================================================================
=======
! Evaluate the damage activation function
!
-----------------------------------------------------------------------------------
------

! Elastic strain: Total - plastic


stran_e = (stran + dstran) - statev(5:4+ntens)

! Start with the effective stress tensor


stress_eff = matmul(Celastic, stran_e)

I1_eff = stress_eff(1) + stress_eff(2) + stress_eff(3)


J2_eff = ((stress_eff(1) - stress_eff(2))**2.0_rp + (stress_eff(3) -
stress_eff(2))**2.0_rp + &
(stress_eff(3) - stress_eff(1))**2.0_rp) / 6.0_rp
do itens = ndi+1,ntens
J2_eff = J2_eff + stress_eff(itens)**2.0_rp
end do

load_func = (3.0_rp * J2_eff + I1_eff * (XC - XT)) / XC / XT !Eq. 44 Melro; Eq.


11 Arefi

!rint = max(1.0_rp,rint) ! BSC

f_fail = load_func - rint ! Eq. 49 Melro; Eq. 10 Arefi

! Evaluate the damage activation function


if( f_fail > 0.0_rp ) then ! Damage state!! Eq. 43
!
! Damage is activated
!
! (vi) Update damage variables, stiffness and stress tensors
!rint = max(load_func,rint) ! BSC
rint = load_func
statev(1) = rint

! Update the damage variable


if( lawco == SM155_AREFI_VERSION ) then
damage = UpdateDamage(statev(2), rint, XT, XC, E, nu)

else if( lawco == SM155_CLASSICAL_VERSION ) then


damage_old = damage
damage = DamageEvolutionLaw(statev(2), rint)
! viscous regularisation
damage = eta_visco/(eta_visco+dtime)*damage_old +
dtime/(eta_visco+dtime)*damage
else if( lawco == SM155_EXPONENTIAL_VERSION ) then
damage_old = damage
damage = DamageEvolutionLaw(statev(2), rint)
! viscous regularisation
damage = eta_visco/(eta_visco+dtime)*damage_old +
dtime/(eta_visco+dtime)*damage
end if

damage = min(damage,0.9999_rp) ! BSC

if( damage >= 0.99999_rp ) then


! The material has failed
damage = 1.0_rp
ddsdde = 0.0_rp
!ddsdde = (1.0_rp - damage)*Celastic
stress = 0.0_rp
else
if( lawco == SM155_AREFI_VERSION ) then
call DamagedElasticMatrix(ndi, nshr, E, nu, G_shear, damage, Cdamaged)
! Update damaged stress tensor
stress = matmul(Cdamaged, stran_e)
! Update the consistent tangent
forall (i = 1:ndi) sdev_eff(i) = stress_eff(i) - I1_eff / 3.0_rp
call TangentEvolvingDamageArefi(Cdamaged, stran_e, damage, E, nu,
G_shear, K_bulk, XT, XC, &
sdev_eff, statev(2), rint, ndi, nshr, dDSdDE)

else if( lawco == SM155_CLASSICAL_VERSION ) then


Cdamaged = (1.0_rp - damage)*Celastic
! Update damaged stress tensor
stress = (1.0_rp - damage)*stress_eff
! Update the consistent tangent
forall (i = 1:ndi) sdev_eff(i) = stress_eff(i) - I1_eff/3.0d0
call TangentEvolvingDamageClassical(Cdamaged, G_shear, K_bulk, XT, XC,
&
stress_eff, sdev_eff, statev(2), rint, ndi, nshr, dDSdDE)

else if( lawco == SM155_EXPONENTIAL_VERSION ) then


call DamagedElasticMatrix(ndi, nshr, E, nu, G_shear, damage, Cdamaged)
! Update damaged stress tensor
stress = matmul(Cdamaged, stran_e)
! Update the consistent tangent
forall (i = 1:ndi) sdev_eff(i) = stress_eff(i) - I1_eff/3.0_rp
call TangentEvolvingDamageExponential(Cdamaged, stran_e, damage, E,
nu, G_shear, K_bulk, XT, XC, &
sdev_eff, statev(2), rint, ndi, nshr, dDSdDE)

end if
end if
!
! Save damage variable
!
statev(3) = damage

else
!
! Damage is not evolving (but is present)
!
if( damage > 0.0_rp ) then
! Damage is present
if( lawco == SM155_AREFI_VERSION ) then
call DamagedElasticMatrix(ndi, nshr, E, nu, G_shear, damage, ddsdde)

else if( lawco == SM155_CLASSICAL_VERSION ) then


ddsdde = (1.0_rp - damage)*Celastic

else if( lawco == SM155_EXPONENTIAL_VERSION ) then


call DamagedElasticMatrix(ndi, nshr, E, nu, G_shear, damage, ddsdde)

end if
stress = matmul(ddsdde, stran_e)
else if( dgamma > 0.0_rp ) then
! Elasto-plastic tangent
! Update Derivative of the accumulated plastic strain with respect to the
plastic multiplier
depb_ddgamma = sqrt(A) - dgamma / 2.0_rp / sqrt(A) * (216.0_rp * G_shear
* J2_trial / zeta_s**3.0_rp + & ! Eq. 32
16.0_rp * (alpha_p**3.0_rp) * K_bulk * I1_trial**2.0_rp / 27.0_rp /
zeta_p**3.0_rp)
depb_ddgamma = sqrt(1.0_rp / (1.0_rp + 2.0_rp * nu_p**2.0_rp) ) *
depb_ddgamma ! Eq. 32

dsigc_ddgamma = hc * depb_ddgamma
! Eq. 30
dsigt_ddgamma = ht * depb_ddgamma
! Eq. 31
dres_dgamma = 2.0_rp * I1_trial/ zeta_p * (dsigc_ddgamma - dsigt_ddgamma)
- & ! Eq. 29
4.0_rp * K_bulk * alpha_p * I1_trial * (syc - syt) / zeta_p**2.0_rp
- &
72.0_rp * G_shear * J2_trial/zeta_s**3.0_rp - 2.0_rp * depb_ddgamma
* (syc * ht + syt * hc)

eta = -dres_dgamma

!---> This is always the same


! Set idendity tensors
I2 = 0.0_rp
I2(1:ndi) = 1.0_rp
! Deviatoric 4th order tensor
I4 = 0.0_rp
do i = 1,ndi
I4(i,i) = 1.0_rp
end do
do i = ndi+1,ntens
I4(i,i) = 0.5_rp
end do
! Set some auxiliary tensors
! <----
do j = 1,ntens
do i = 1,ntens
IoI(i,j) = I2(i)*I2(j)
SoI(i,j) = sdev_trial(i)*I2(j)
IoS(i,j) = sdev_trial(j)*I2(i)
SoS(i,j) = sdev_trial(i)*sdev_trial(j)
end do
end do

! Scalar factors for the consistent tangent operator


beta = 2.0_rp*G_shear/zeta_s
! Eq. 34
phi = K_bulk/zeta_p -
4.0_rp*K_bulk**2*alpha_p*I1_trial*(syc-syt)/zeta_p**3/eta ! Eq. 34
rho = 36.0_rp*K_bulk*G_shear*(syc-syt)/eta/zeta_s**2/zeta_p
! Eq. 34
chi = 72.0_rp*G_shear**2/eta/zeta_s**4
! Eq. 34
psi = 8.0_rp*K_bulk*G_shear*alpha_p*I1_trial/eta/zeta_p**2/zeta_s**2
! Eq. 34
! Consistent Tangent
dDSdDE = beta*I4 + (phi-beta/3.0_rp)*IoI - rho*SoI - chi*SoS - psi*IoS
! Eq. 33

end if
end if

end subroutine umat

!
===================================================================================
========
! Subroutine to determine current yield stresses in both tension C
! and compression as a function of equivalent plastic strain C
!
! LTYPE = 1, IT READS TENSION FILE C
! LTYPE = -1, IT READS COMPRESSION FILE C
!
!
===================================================================================
========

SUBROUTINE YIELCURV(LTYPE,EQPLAS,SY,H)

implicit none

integer(ip), intent(in) :: LTYPE


real(rp), intent(in) :: EQPLAS
real(rp), intent(out) :: SY,H

real(rp) :: EQPLAS0,EQPLAS1,SY0,SY1
integer(ip) :: I,j
integer(ip) :: unit
integer(ip), parameter :: NCT= 50_ip
integer(ip), parameter :: NCC= 67_ip
real(rp) :: YCT(NCT,2),YCC(NCC,2)
character(len=100) :: filename
!
! Find on the Table the Corresponding Yield Stress
!
IF(LTYPE.EQ.1) THEN
! Read file
filename = "yield_t.txt"
j = 0_ip
unit = 968686_ip
open(unit, file=filename, status='old', iostat=j)
if (j /= 0) then
write(*, *) "Error opening the file"
stop
end if
do i = 1,NCT
read(unit,*) YCT(i,:)
end do
close(unit)
!
H = 1.0e-10_rp
SY = YCT(NCT,2)
DO I=1,NCT-1
IF (EQPLAS.LT.YCT(I+1,1)) THEN
SY0 = YCT(I,2)
SY1 = YCT(I+1,2)
EQPLAS0 = YCT(I,1)
EQPLAS1 = YCT(I+1,1)
H = (SY1-SY0) / (EQPLAS1-EQPLAS0)
SY = (EQPLAS-EQPLAS0)*H + SY0
GOTO 20
ENDIF
ENDDO
ELSE
! Read file
filename = "yield_c.txt"
j = 0_ip
unit = 968687_ip
open(unit, file=filename, status='old', iostat=j)
if (j /= 0) then
write(*, *) "Error opening the file"
stop
end if
do i = 1,NCC
read(unit,*) YCC(i,:)
end do
close(unit)
H = 1.0e-10_rp
SY = YCC(NCC,2)
DO I=1,NCC-1
IF (EQPLAS.LT.YCC(I+1,1)) THEN
SY0 = YCC(I,2)
SY1 = YCC(I+1,2)
EQPLAS0 = YCC(I,1)
EQPLAS1 = YCC(I+1,1)
H = (SY1-SY0) / (EQPLAS1-EQPLAS0)
SY = (EQPLAS-EQPLAS0)*H + SY0
GOTO 20
ENDIF
ENDDO
ENDIF
20 CONTINUE
RETURN

END SUBROUTINE YIELCURV

!
===================================================================================
========
! This subroutine computes the elastic matrix for the damaged material
!
! Igor A. Rodrigues Lopes, Oct 2023
! [email protected]
!
===================================================================================
========

subroutine DamagedElasticMatrix(ndi, nshr, E, nu, G, damage, ddsdde)

implicit none

integer(ip), intent(in) :: ndi, nshr !< Number of direct and shear


components in a symmetric tensor.
real(rp), intent(in) :: E, nu, G !< Young modulus and Poisson
coefficient
real(rp), intent(in) :: damage
real(rp), intent(out) :: ddsdde(ndi+nshr,ndi+nshr)

real(rp) :: Gd, lambdad !< Elastic matrix


integer :: i

! Damaged shear modulus and damaged lambda


Gd = E * (1.0_rp - damage) * (1.0_rp - nu * (1.0_rp - damage)) / &
(1.0_rp + nu * (1.0_rp - damage)) / (1.0_rp - 2.0_rp * nu * (1.0_rp -
damage))
lambdad = E * nu * (1.0_rp - damage)**2.0_rp / (1.0_rp + nu * (1.0_rp -
damage)) / (1.0_rp - 2.0_rp * nu * (1.0_rp - damage))
ddsdde = 0.0_rp
ddsdde(1:ndi,1:ndi) = lambdad
forall (i=1:ndi) ddsdde(i,i) = Gd
forall (i=ndi+1:ndi+nshr) ddsdde(i,i) = (1.0_rp - damage) * G

end subroutine DamagedElasticMatrix

!
===================================================================================
========
! This subroutine computes the consistent tangent for the damaged material
!
! Igor A. Rodrigues Lopes, Oct 2023
! [email protected]
!
===================================================================================
========

subroutine TangentEvolvingDamageArefi(Cdamaged, stran_e, damage, E, nu, G, K, XT,


XC, &
sdev_eff, eps_f, r, ndi, nshr, dDSdDE)

implicit none

integer, intent(in) :: ndi, nshr !! Number of direct and


shear components in a symmetric tensor
real(rp), intent(in) :: Cdamaged(ndi+nshr,ndi+nshr) !! Damaged elastic matrix
real(rp), intent(in) :: stran_e(ndi+nshr) !! Strain vector
real(rp), intent(in) :: damage, E, nu, G, K, XT, XC, eps_f, r !! Scalar
parameters
real(rp), intent(in) :: sdev_eff(ndi+nshr) !! Deviatoric effective
stress vector
real(rp), intent(out) :: dDSdDE(ndi+nshr,ndi+nshr)

real(rp) :: denom, dddr, dGddd, dlambdaddd


real(rp) :: drde(ndi+nshr)
real(rp) :: dCmdd(ndi+nshr,ndi+nshr)
integer :: i, j, l

! Derivative of damage wrt the internal variable


dddr = DerivDamage(eps_f, r, XT, XC, E, nu)
! Derivative of the internal variable wrt the strain
drde = 6.0_rp * G / XT / XC * sdev_eff
do i = 1, ndi
drde(i) = drde(i) + 3.0_rp * K * (XC - XT) / XT / XC
end do
! Derivative of the damaged elastic matrix wrt the damage variable
denom = (1.0_rp + nu * (1.0_rp - damage))**2 * (1.0_rp - 2.0_rp * nu * (1.0_rp
- damage))**2.0_rp
dGddd = -E * (3.0_rp * nu**2.0_rp * (1.0_rp - damage)**2.0_rp - 2.0_rp *
(1.0_rp - damage)*nu + 1.0_rp) / denom
dlambdaddd = -E * nu * (1.0_rp - damage) * (2.0_rp - nu * (1.0_rp - damage)) /
denom

dCmdd = 0.0_rp
dCmdd(1:ndi,1:ndi) = dlambdaddd
do i = 1, ndi
dCmdd(i,i) = dGddd
end do
do i = ndi+1, ndi+nshr
dCmdd(i,i) = -G
end do
! Tangent
dDSdDE = 0.0_rp
do i = 1,ndi+nshr
do j = 1,ndi+nshr
do l = 1,ndi+nshr
dDSdDE(i,j) = dDSdDE(i,j) + dCmdd(i,l) * stran_e(l) * drde(j)
end do
end do
end do
dDSdDE = dddr*dDSdDE
dDSdDE = dDSdDE + Cdamaged

end subroutine TangentEvolvingDamageArefi

!
===================================================================================
========
! Reference: Damage evolution law proposed by Arefi et al. (2018).
!
! This function updates the damage variable according to the internal variable
_rint_.
! It is based on the damage evolution law proposed by Arefi et al. (2018).
! Bilinear isotropic damage
!
! Igor A. Rodrigues Lopes, Oct 2023
! [email protected]; [email protected]
! Reviewed: OK
!
===================================================================================
========

function UpdateDamage(eps_f, rint, XT, XC, E, nu) result(updDamage)

real(rp), intent(in) :: eps_f !< Strain at failure


real(rp), intent(in) :: rint !< Internal variable
real(rp), intent(in) :: XT, XC !< Tension/compression strengths
real(rp), intent(in) :: E, nu !< Young Modulus and Poisson ratio

real(rp) :: eps_0, eps_eq


real(rp) :: a, b, c, q, p, u
real(rp) :: updDamage
! Parameters for the equivalent strain ! Eq. 26
eps_0 = XT / E
a = nu * XT / E / (eps_f - eps_0)
b = (E / (1.0_rp + nu))**2.0_rp
c = E / (1.0_rp - 2.0_rp * nu) * (XC - XT)
q = 2.0_rp * a * (1.0_rp - a) * b * eps_f + (1.0_rp + 2.0_rp * a) * c
p = b * (1.0_rp - a)**2.0_rp
u = b * (a * eps_f)**2.0_rp - 2.0_rp * a * c * eps_f - rint * XC * XT

eps_eq = (-q + sqrt(q**2.0_rp - 4.0_rp * p * u)) / (2.0_rp * p) ! Eq. 27

! Updated damage variable


updDamage = eps_f * (eps_eq - eps_0) / eps_eq / (eps_f - eps_0) ! Eq. 2

end function UpdateDamage

!
===================================================================================
========
! Reference: Damage evolution law proposed by Arefi et al. (2018).
!
! This function computes the derivative of the damage variable wrt to the
internal variable
! _rint_.
! It is based on the damage evolution law proposed by Arefi et al. (2018).
!
! Igor A. Rodrigues Lopes, Oct 2023
! [email protected]; [email protected]
! Reviewed: OK
!
===================================================================================
========

function DerivDamage(eps_f, rint, XT, XC, E, nu) result(deriDamage)

real(rp), intent(in) :: eps_f !< Strain at failure


real(rp), intent(in) :: rint !< Internal variable
real(rp), intent(in) :: XT, XC !< Tension/compression strength
real(rp), intent(in) :: E, nu !< Young Modulus and Poisson ratio

real(rp) :: eps_0, eps_eq


real(rp) :: a, b, c, q, p, u
real(rp) :: dddeeq, deeqdu, dudrint
real(rp) :: deriDamage

! Parameters for the equivalent strain ! Eq. 26


eps_0 = XT / E
a = nu * XT / E / (eps_f - eps_0)
b = (E / (1.0_rp + nu))**2.0_rp
c = E / (1.0_rp - 2.0_rp * nu) * (XC - XT)
q = 2.0_rp * a * (1.0_rp - a) * b * eps_f + (1.0_rp + 2.0_rp * a) * c
p = b * (1.0_rp - a)**2.0_rp
u = b * (a * eps_f)**2.0_rp - 2.0_rp * a * c * eps_f - rint * XC * XT

eps_eq = (-q + sqrt(q**2.0_rp - 4.0_rp * p * u)) / (2.0_rp * p) ! Eq. 27

dddeeq = eps_f / eps_eq / (eps_f - eps_0) - eps_f * (eps_eq - eps_0) /


eps_eq**2.0_rp / (eps_f - eps_0)
deeqdu = -1.0_rp / sqrt(q**2.0_rp - 4.0_rp * p * u)
dudrint = -XC * XT

! Derivative of the damage variable wrt internal variable


deriDamage = dddeeq * deeqdu * dudrint

end function DerivDamage

!
===================================================================================
========
! Reference: Exponential Damage (Federico)
!
!
! Subroutine to determine the damage parameter _A_ by solving the equation:
! int_1^\infty (Y*dddr) dr - Gc/Le = 0
! using the secant method [Melro, PhD Thesis, 2011]
!
! Initial version:
! Routine SMPARAMA, by Federico Danzi
! Code refactoring:
! Igor A. Rodrigues Lopes, Dec 2023
! [email protected]
!
===================================================================================
=======

SUBROUTINE GetDamageParameterAExponential(A_new, E, v, XT, XC, Gc, Le)

implicit none

real(rp), intent(in) :: E, v, XT, XC, Gc, Le !! Material properties


real(rp), intent(out) :: A_new !! Damage parameter
integer(ip) :: icount, maxiter !! Iteration counter and max
allowed iterations
real(rp) :: resid, tol !! Residual and convergence
tolerance (relative)
real(rp) :: A_n, A_old, int_new, int_old !! Values of A and
associated integrals

! Initialisations
tol = 0.01_rp
maxiter = 10000_ip
!
A_new = (2.0_rp * Le * XT**2.0_rp)/(2.0_rp * E * Gc - Le * XT**2.0_rp)
A_old = 0.5_rp * A_new
! Compute the integrals with both values of A
call SimpsonIntegralExponential(int_old, A_old, E, v, XT, XC, Gc/Le)
call SimpsonIntegralExponential(int_new, A_new, E, v, XT, XC, Gc/Le)
! Initialise the residual and enter the iterative loop
resid = abs(int_new - Gc / Le) / (Gc / Le)
icount = 0_ip
do while (resid > tol .and. icount <= maxiter)
! Update the value of A with the secant method
A_n = exp(log(A_new) - (log(int_new) - log(Gc/Le)) * (log(A_new) -
log(A_old)) / (log(int_new) - log(int_old)))
A_old = A_new
A_new = A_n
int_old = int_new
! Compute the integral with the new value of A
call SimpsonIntegralExponential(int_new, A_n, E, v, XT, XC, Gc/Le)
! Update the residual and the iteration counter
resid = abs(int_new - Gc / Le) / (Gc / Le)
icount = icount + 1
end do

end subroutine GetDamageParameterAExponential

!
===================================================================================
========
! Reference: Exponential Damage (Federico)
!
!
! Subroutine to obtain the improper integral:
! int_1^\infty (Y*dddr) dr
! given a damage parameter A. The integral is computed using the Simpson method.
!
! Initial version:
! Routine SIMPSONMATRIX, by Federico Danzi, and SMINT, by Antonio Melro.
! Code refactoring as SimpsonIntegral:
! Igor A. Rodrigues Lopes, Dec 2023
! [email protected]
!
===================================================================================
=======

subroutine SimpsonIntegralExponential(int_new, A, E, v, XT, XC, GcdLe)

implicit none
! Arguments
real(rp), intent(in) :: E, v, XT, XC, GcdLe
!! Material properties
real(rp), intent(in) :: A
!! Damage parameter
real(rp), intent(out) :: int_new
!! Integral value
! Local variables
real(rp) :: int_old, Dr, d, dddr, sigma, s11_eff, YUN
!! Integration variables
real(rp), dimension(3) :: r, integrand
!! Function with Damage Evolution Law
integer(ip), parameter :: miter_1 = 10_ip, miter_2 = 10000_ip
integer(ip) :: icount_1, icount_2, i, n_steps
!! Integer variables
real(8), parameter :: tol = 0.001_rp, Kfactor = 10000.0_rp
!! Convergence tolerance
!
===================================================================================
=======
! Initialisations
int_old = 1.0_rp
int_new = 0.0_rp
n_steps = 100_ip
! Initialise loop where the integral is computed with different step sizes
icount_1 = 0
do while (abs((int_new - int_old) / GcdLe) > tol .and. icount_1 < miter_1)
r(3) = 1.0_rp
sigma = XT
Dr = -1.0_rp / real(n_steps,rp) / A * log(1.0_rp / Kfactor)
int_old = int_new
int_new = 0.0_rp
icount_2 = 0_ip
do while (sigma > XT / Kfactor .and. icount_2 < miter_2)
r(1) = r(3)
r(2) = r(1) + Dr
r(3) = r(2) + Dr
do i = 1, 3
d = DamageEvolutionLaw(A, r(i))
dddr = FMDDAMAGEDR(A, r(i))
s11_eff = (XT - XC + sqrt((XC - XT)**2.0_rp + 4.0_rp * XT * XC *
r(i))) / 2.0_rp
YUN = s11_eff**2.0_rp / 2.0_rp / E * &
(2.0_rp * v**2.0_rp * d**2.0_rp + (1.0_rp - v * (1.0_rp - d) *
(1.0_rp + 2.0_rp * v))**2.0d0) / &
(1.0_rp + v * (1.0_rp - d))**2.0_rp / (1.0_rp - 2.0_rp * v *
(1.0_rp - d))**2.0_rp
integrand(i) = dddr * YUN
end do
int_new = int_new + (integrand(1) + 4.0_rp * integrand(2) + integrand(3))
* Dr / 3.0_rp
sigma = (1.0_rp - d) * (1.0_rp - v * (1.0_rp - d) * (1.0_rp + 2.0_rp *
v)) * s11_eff / &
(1.0_rp + v * (1.0_rp - d)) / (1.0_rp - 2.0_rp * v * (1.0_rp - d))
icount_2 = icount_2 + 1_ip
end do
n_steps = n_steps * 2_ip
icount_1 = icount_1 + 1_ip
end do

end subroutine SimpsonIntegralExponential

!
===================================================================================
========
! Reference: Classical Damage
!
!
! Subroutine to determine the damage parameter _A_ by solving the equation:
! int_1^\infty (Y*dddr) dr - Gc/Le = 0
! using the secant method [Melro, PhD Thesis, 2011]
!
! Initial version:
! Routine SMPARAMA, by Federico Danzi
! Code refactoring:
! Igor A. Rodrigues Lopes, Dec 2023
! [email protected]
!
===================================================================================
=======

SUBROUTINE GetDamageParameterAClassical(A_new, E, XT, XC, Gc, Le)

implicit none

real(rp), intent(in) :: E, XT, XC, Gc, Le !! Material properties


real(rp), intent(out) :: A_new !! Damage parameter
integer(ip) :: icount, maxiter !! Iteration counter and max
allowed iterations
real(rp) :: resid, tol !! Residual and convergence
tolerance (relative)
real(rp) :: A_n, A_old, int_new, int_old !! Values of A and
associated integrals

! Initialisations
tol = 0.01_rp
maxiter = 10000_ip
!
A_new = (2.0_rp * Le * XT**2.0_rp)/(2.0_rp * E * Gc - Le * XT**2.0_rp)
A_old = 0.5_rp * A_new
! Compute the integrals with both values of A
call SimpsonIntegralClassical(int_old, A_old, E, XT, XC, Gc/Le)
call SimpsonIntegralClassical(int_new, A_new, E, XT, XC, Gc/Le)
! Initialise the residual and enter the iterative loop
resid = abs(int_new - Gc / Le) / (Gc / Le)
icount = 0_ip
do while (resid > tol .and. icount <= maxiter)
! Update the value of A with the secant method
A_n = exp(log(A_new) - (log(int_new) - log(Gc/Le)) * (log(A_new) -
log(A_old)) / (log(int_new) - log(int_old)))
A_old = A_new
A_new = A_n
int_old = int_new
! Compute the integral with the new value of A
call SimpsonIntegralClassical(int_new, A_n, E, XT, XC, Gc/Le)
! Update the residual and the iteration counter
resid = abs(int_new - Gc / Le) / (Gc / Le)
icount = icount + 1
end do

end subroutine GetDamageParameterAClassical

!
===================================================================================
========
! Reference: Exponential Damage (Federico)
! Classical Damage
!
! Subroutine to obtain the improper integral:
! int_1^\infty (Y*dddr) dr
! given a damage parameter A. The integral is computed using the Simpson method.
!
! Initial version:
! Routine SIMPSONMATRIX, by Federico Danzi, and SMINT, by Antonio Melro.
! Code refactoring as SimpsonIntegral:
! Igor A. Rodrigues Lopes, Dec 2023
! [email protected]
!
===================================================================================
=======
subroutine SimpsonIntegralClassical(int_new, A, E, XT, XC, GcdLe)

implicit none
! Arguments
real(rp), intent(in) :: E, XT, XC, GcdLe
!! Material properties
real(rp), intent(in) :: A
!! Damage parameter
real(rp), intent(out) :: int_new
!! Integral value
! Local variables
real(rp) :: int_old, Dr, d, dddr, sigma, s11_eff, YUN
!! Integration variables
real(rp) :: r(3), integrand(3)
!! Function with Damage Evolution Law
integer(ip), parameter :: miter_1 = 10_ip, miter_2 = 10000_ip
integer(ip) :: n_steps, icount_1, icount_2, i
!! Integer variables
real(rp), parameter :: tol = 0.001_rp, Kfactor = 10000.0_rp
!! Convergence tolerance

! Initialisations
int_old = 1.0_rp
int_new = 0.0_rp
n_steps = 100_ip
! Initialise loop where the integral is computed with different step sizes
icount_1 = 0_ip
do while (abs((int_new-int_old)/GcdLe) > tol .and. icount_1 < miter_1)
r(3) = 1.0_rp
sigma = XT
Dr = -1.0_rp / real(n_steps,rp) / A * log(1.0_rp / Kfactor)
int_old = int_new
int_new = 0.0_rp
icount_2 = 0_ip
do while (sigma > XT / Kfactor .and. icount_2 < miter_2)
r(1) = r(3)
r(2) = r(1) + Dr
r(3) = r(2) + Dr
do i = 1,3
d = DamageEvolutionLaw(A, r(i))
dddr = FMDDAMAGEDR(A, r(i))
s11_eff = (XT - XC + sqrt((XC - XT)**2.0_rp + 4.0_rp * XT * XC *
r(i))) / 2.0_rp
YUN = s11_eff**2.0_rp / 2.0_rp / E
integrand(i) = dddr * YUN
end do
int_new = int_new + (integrand(1) + 4.0_rp * integrand(2) + integrand(3))
* Dr / 3.0_rp
sigma = (1.0_rp - d) * s11_eff
icount_2 = icount_2 + 1_ip
end do
n_steps = n_steps * 2_ip
icount_1 = icount_1 + 1_ip
end do

end subroutine SimpsonIntegralClassical

!
===================================================================================
========
! Reference: Exponential Damage (Federico)
! Classical Damage
!
! Function with Damage Evolution Law
! ! Eq. 53 Melro et al. 2013
! ! Eq. 15 Arefi et al. 2018
!
! root = sqrt(7.0_rp + 2.0_rp * r_m**2.0_rp)
! d_m = 1.0_rp - exp(A_m * (3.0_rp - root)) / (root - 2.0_rp)
!
===================================================================================
========

function DamageEvolutionLaw(A_m, r_m) result(d_m)

real(rp), intent(in) :: A_m !< Damage parameter


real(rp), intent(in) :: r_m !< Damage threshold
real(rp) :: d_m !< Damage variable

real(rp) :: root

root = sqrt(7.0_rp + 2.0_rp * r_m**2.0_rp) - 2.0_rp


d_m = 1.0_rp - exp(A_m * (1.0_rp - root)) / root

end function DamageEvolutionLaw

!
===================================================================================
========
! Reference: Exponential Damage (Federico)
! Classical Damage
!
! Function with Derivative of Damage Evolution Law -->> dddr
!
===================================================================================
========

function FMDDAMAGEDR(A_m, r_m) result(dddr)

real(rp), intent(in) :: A_m !< Damage parameter


real(rp), intent(in) :: r_m !< Damage threshold
real(rp) :: dddr

real(rp) :: root

root = sqrt(7.0_rp + 2.0_rp * r_m**2.0_rp) - 2.0_rp


dddr = 2.0_rp * r_m * exp(A_m * (1.0_rp - root)) * (A_m + 1.0_rp / root) / root
/ (root + 2.0_rp)

end function FMDDAMAGEDR

!
===================================================================================
========
! Reference: Exponential Damage (Federico)
!
! This subroutine computes the consistent tangent for the damaged material
!
!
===================================================================================
========

subroutine TangentEvolvingDamageExponential(Cdamaged, stran_e, damage, E, nu, G,


K, XT, XC, &
sdev_eff, A, r, ndi, nshr, dDSdDE)
implicit none

integer(ip), intent(in) :: ndi, nshr !! Number of direct and


shear components in a symmetric tensor
real(rp), intent(in) :: Cdamaged(ndi+nshr,ndi+nshr) !! Damaged elastic
matrix
real(rp), intent(in) :: E, nu, G, K, XT, XC, A, r !! Scalar
parameters
real(rp), intent(in) :: damage
real(rp), intent(in) :: stran_e(ndi+nshr)
real(rp), intent(in) :: sdev_eff(ndi+nshr) !! Total and Deviatoric
effective stress vector
real(rp), intent(out) :: dDSdDE(ndi+nshr,ndi+nshr)

real(rp) :: dddr, denom, dGddd, dlambdaddd


real(rp) :: drde(ndi+nshr)
real(rp) :: dCmdd(ndi+nshr,ndi+nshr)
integer(ip) :: i, j, l

! Derivative of damage wrt the internal variable


dddr = FMDDAMAGEDR(A, r)
! Derivative of the internal variable wrt the strain
drde = 6.0_rp * G / XT / XC * sdev_eff
forall(i=1:ndi) drde(i) = drde(i) + 3.0_rp * K * (XC - XT) / XT / XC
! Derivative of the damaged elastic matrix wrt the damage variable
denom = (1.0_rp + nu*( 1.0_rp - damage))**2.0_rp * (1.0_rp - 2.0_rp * nu *
(1.0_rp - damage))**2.0_rp
dGddd = -E * (3.0_rp * nu**2.0_rp * (1.0_rp - damage)**2.0_rp - 2.0_rp *
(1.0_rp - damage) * nu + 1.0_rp) / denom
dlambdaddd = -E * nu * (1.0_rp - damage) * (2.0_rp - nu * (1.0_rp - damage)) /
denom
!
dCmdd = 0.0_rp
dCmdd(1:ndi,1:ndi) = dlambdaddd
forall(i=1:ndi) dCmdd(i,i) = dGddd
forall(i=ndi+1:ndi+nshr) dCmdd(i,i) = -G
! Final tangent:
dDSdDE = 0.0_rp
do i = 1, ndi+nshr
do j = 1, ndi+nshr
do l = 1, ndi+nshr
dDSdDE(i,j) = dDSdDE(i,j) + dCmdd(i,l) * stran_e(l) * drde(j)
end do
end do
end do
dDSdDE = dddr*dDSdDE
dDSdDE = dDSdDE + Cdamaged

end subroutine TangentEvolvingDamageExponential

!
===================================================================================
========
! Reference: Classical Damage
!
! This subroutine computes the consistent tangent for the damaged material
!
!
===================================================================================
========

subroutine TangentEvolvingDamageClassical(Cdamaged, G, K, XT, XC, &


stress_eff, sdev_eff, A, r, ndi, nshr, dDSdDE)

implicit none

integer(ip), intent(in) :: ndi, nshr !! Number of direct and


shear components in a symmetric tensor
real(rp), intent(in) :: Cdamaged(ndi+nshr,ndi+nshr) !! Damaged elastic
matrix
real(rp), intent(in) :: G, K, XT, XC, A, r !! Scalar parameters
real(rp), intent(in) :: stress_eff(ndi+nshr)
real(rp), intent(in) :: sdev_eff(ndi+nshr) !! Total and Deviatoric
effective stress vector
real(rp), intent(out) :: dDSdDE(ndi+nshr,ndi+nshr)

real(rp) :: dddr
real(rp) :: drde(ndi+nshr)
real(rp) :: ddde(ndi+nshr)
integer(ip) :: i, j

! Derivative of damage wrt the internal variable


dddr = FMDDAMAGEDR(A, r)

! Derivative of the internal variable wrt the strain


drde = 6.0_rp * G / XT / XC * sdev_eff
forall(i=1:ndi) drde(i) = drde(i) + 3.0_rp * K * (XC - XT) / XT / XC

! Derivative of the damage variable wrt the strain


ddde = dddr*drde

! Final tangent
dDSdDE = 0.0d0
do i = 1,ndi+nshr
do j = 1,ndi+nshr
dDSdDE(i,j) = - stress_eff(i) * ddde(j)
end do
end do
dDSdDE = dDSdDE + Cdamaged

end subroutine TangentEvolvingDamageClassical

!--------------------------------------------------------------
! Helper function to compute Determinant of 3x3 matrix
!--------------------------------------------------------------

SUBROUTINE determinant(matrix, det)


IMPLICIT NONE

REAL(rp), INTENT(IN) :: matrix(3, 3)


REAL(rp), INTENT(OUT):: det

det = matrix(1,1) * (matrix(2,2) * matrix(3,3) &


- matrix(3,2) * matrix(2, 3)) - matrix(1,2) * (matrix(2,1) &
* matrix(3,3) - matrix(2,3) * matrix(3,1)) + matrix(1,3) &
* (matrix(2,1) * matrix(3,2) - matrix(2,2) * matrix(3,1))
END SUBROUTINE determinant

!--------------------------------------------------------------
! Helper function to compute inverse of 3x3 matrix
!--------------------------------------------------------------
SUBROUTINE matInv(matrix, inv)
IMPLICIT NONE

REAL(rp), INTENT(IN) :: matrix(3, 3)


REAL(rp), INTENT(OUT) :: inv(3, 3)
REAL(rp) :: J

inv(1,1) = matrix(2,2)*matrix(3,3) - matrix(3,2)*matrix(2,3)


inv(1,2) = matrix(3,2)*matrix(1,3) - matrix(1,2)*matrix(3,3)
inv(1,3) = matrix(1,2)*matrix(2,3) - matrix(2,2)*matrix(1,3)
inv(2,1) = matrix(3,1)*matrix(2,3) - matrix(2,1)*matrix(3,3)
inv(2,2) = matrix(1,1)*matrix(3,3) - matrix(3,1)*matrix(1,3)
inv(2,3) = matrix(2,1)*matrix(1,3) - matrix(1,1)*matrix(2,3)
inv(3,1) = matrix(2,1)*matrix(3,2) - matrix(3,1)*matrix(2,2)
inv(3,2) = matrix(3,1)*matrix(1,2) - matrix(1,1)*matrix(3,2)
inv(3,3) = matrix(1,1)*matrix(2,2) - matrix(2,1)*matrix(1,2)

CALL determinant(matrix, J)
inv(:, :) = inv(:, :) / J

END SUBROUTINE matInv

subroutine Tau2Piola(F_dd, S_v, C_vv, P_dd, A1_dddd)


real(rp), intent(in) :: F_dd(3,3), S_v(6), C_vv(6,6)
real(rp), intent(out) :: P_dd(3,3), A1_dddd(3,3,3,3)
real(rp) :: J, Finv_dd(3,3), T_dd(3,3), C_dddd(3,3,3,3)
integer(ip) :: ii, jj, kk, ll, mm, pp
real(rp), parameter :: I_dd(3,3) =
reshape([1.0_rp,0.0_rp,0.0_rp,0.0_rp,1.0_rp,0.0_rp,0.0_rp,0.0_rp,1.0_rp],[3,3])

! Kinematic variables
call matInv(F_dd, Finv_dd)
call determinant(F_dd,J)
!
! Abaqus UMAT voigt: 11 22 33 12 13 23
! Abaqus ordering: 1 2 3 4 5 6
!
! Cauchy (S) to Kirchoff (T)
T_dd(1,1) = J * S_v(1) !Ok
T_dd(2,1) = J * S_v(4) !Ok
T_dd(3,1) = J * S_v(5) !Ok
T_dd(1,2) = J * S_v(4) !Ok
T_dd(2,2) = J * S_v(2) !Ok
T_dd(3,2) = J * S_v(6) !Ok
T_dd(1,3) = J * S_v(5) !Ok
T_dd(2,3) = J * S_v(6) !Ok
T_dd(3,3) = J * S_v(3) !Ok

! Kirchoff (T) to First-Piola Kirchoff (P)


P_dd = matmul(T_dd, transpose(Finv_dd))

! Decompress dtau/dF (Jaumann rate)


C_dddd(1,1,1,1) = C_vv(1,1)
C_dddd(1,1,1,2) = C_vv(1,4)
C_dddd(1,1,1,3) = C_vv(1,5)
C_dddd(1,1,2,1) = C_vv(1,4)
C_dddd(1,1,2,2) = C_vv(1,2)
C_dddd(1,1,2,3) = C_vv(1,6)
C_dddd(1,1,3,1) = C_vv(1,5)
C_dddd(1,1,3,2) = C_vv(1,6)
C_dddd(1,1,3,3) = C_vv(1,3)

C_dddd(2,2,1,1) = C_vv(2,1)
C_dddd(2,2,1,2) = C_vv(2,4)
C_dddd(2,2,1,3) = C_vv(2,5)
C_dddd(2,2,2,1) = C_vv(2,4)
C_dddd(2,2,2,2) = C_vv(2,2)
C_dddd(2,2,2,3) = C_vv(2,6)
C_dddd(2,2,3,1) = C_vv(2,5)
C_dddd(2,2,3,2) = C_vv(2,6)
C_dddd(2,2,3,3) = C_vv(2,3)

C_dddd(3,3,1,1) = C_vv(3,1)
C_dddd(3,3,1,2) = C_vv(3,4)
C_dddd(3,3,1,3) = C_vv(3,5)
C_dddd(3,3,2,1) = C_vv(3,4)
C_dddd(3,3,2,2) = C_vv(3,2)
C_dddd(3,3,2,3) = C_vv(3,6)
C_dddd(3,3,3,1) = C_vv(3,5)
C_dddd(3,3,3,2) = C_vv(3,6)
C_dddd(3,3,3,3) = C_vv(3,3)

C_dddd(1,2,1,1) = C_vv(4,1)
C_dddd(1,2,1,2) = C_vv(4,4)
C_dddd(1,2,1,3) = C_vv(4,5)
C_dddd(1,2,2,1) = C_vv(4,4)
C_dddd(1,2,2,2) = C_vv(4,2)
C_dddd(1,2,2,3) = C_vv(4,6)
C_dddd(1,2,3,1) = C_vv(4,5)
C_dddd(1,2,3,2) = C_vv(4,6)
C_dddd(1,2,3,3) = C_vv(4,3)

C_dddd(2,1,1,1) = C_vv(4,1)
C_dddd(2,1,1,2) = C_vv(4,4)
C_dddd(2,1,1,3) = C_vv(4,5)
C_dddd(2,1,2,1) = C_vv(4,4)
C_dddd(2,1,2,2) = C_vv(4,2)
C_dddd(2,1,2,3) = C_vv(4,6)
C_dddd(2,1,3,1) = C_vv(4,5)
C_dddd(2,1,3,2) = C_vv(4,6)
C_dddd(2,1,3,3) = C_vv(4,3)

C_dddd(1,3,1,1) = C_vv(5,1)
C_dddd(1,3,1,2) = C_vv(5,4)
C_dddd(1,3,1,3) = C_vv(5,5)
C_dddd(1,3,2,1) = C_vv(5,4)
C_dddd(1,3,2,2) = C_vv(5,2)
C_dddd(1,3,2,3) = C_vv(5,6)
C_dddd(1,3,3,1) = C_vv(5,5)
C_dddd(1,3,3,2) = C_vv(5,6)
C_dddd(1,3,3,3) = C_vv(5,3)

C_dddd(3,1,1,1) = C_vv(5,1)
C_dddd(3,1,1,2) = C_vv(5,4)
C_dddd(3,1,1,3) = C_vv(5,5)
C_dddd(3,1,2,1) = C_vv(5,4)
C_dddd(3,1,2,2) = C_vv(5,2)
C_dddd(3,1,2,3) = C_vv(5,6)
C_dddd(3,1,3,1) = C_vv(5,5)
C_dddd(3,1,3,2) = C_vv(5,6)
C_dddd(3,1,3,3) = C_vv(5,3)

C_dddd(3,2,1,1) = C_vv(6,1)
C_dddd(3,2,1,2) = C_vv(6,4)
C_dddd(3,2,1,3) = C_vv(6,5)
C_dddd(3,2,2,1) = C_vv(6,4)
C_dddd(3,2,2,2) = C_vv(6,2)
C_dddd(3,2,2,3) = C_vv(6,6)
C_dddd(3,2,3,1) = C_vv(6,5)
C_dddd(3,2,3,2) = C_vv(6,6)
C_dddd(3,2,3,3) = C_vv(6,3)

C_dddd(2,3,1,1) = C_vv(6,1)
C_dddd(2,3,1,2) = C_vv(6,4)
C_dddd(2,3,1,3) = C_vv(6,5)
C_dddd(2,3,2,1) = C_vv(6,4)
C_dddd(2,3,2,2) = C_vv(6,2)
C_dddd(2,3,2,3) = C_vv(6,6)
C_dddd(2,3,3,1) = C_vv(6,5)
C_dddd(2,3,3,2) = C_vv(6,6)
C_dddd(2,3,3,3) = C_vv(6,3)

! dTau/dF to dP/dF
A1_dddd = 0.0_rp
do ii = 1, 3
do jj = 1, 3
do kk = 1, 3
do ll = 1, 3
A1_dddd(ii,jj,kk,ll) = 0.0_rp
do pp = 1, 3
do mm = 1, 3
A1_dddd(ii,jj,kk,ll) = A1_dddd(ii,jj,kk,ll) + &
J * C_dddd(ii,pp,kk,mm) * Finv_dd(ll,mm) *
Finv_dd(jj,pp) + &
0.5_rp * I_dd(ii,kk) * Finv_dd(ll,mm) * T_dd(mm,pp) *
Finv_dd(jj,pp) + &
0.5_rp * I_dd(pp,kk) * Finv_dd(ll,mm) * T_dd(ii,mm) *
Finv_dd(jj,pp)
enddo
A1_dddd(ii,jj,kk,ll) = A1_dddd(ii,jj,kk,ll) - &
0.5_rp * Finv_dd(ll,ii) * T_dd(kk,pp) * Finv_dd(jj,pp) -
0.5_rp * Finv_dd(ll,pp) * T_dd(ii,kk) * Finv_dd(jj,pp) - &
T_dd(ii,pp) * Finv_dd(ll,pp) * Finv_dd(jj,kk)
enddo
enddo
enddo
enddo
enddo

end subroutine Tau2Piola

subroutine sld_abaqus2alya(stress,ddsdde,gpstr,gpdds)
use mod_sld_stress_model_comput, only : SM_tensor_to_voigt_fourth
use mod_sld_stress_model_comput, only : SM_Voigt2Tensor_2nd, SM_V2T_KINETIC

implicit none

real(rp), intent(in) :: stress(6)


real(rp), intent(in) :: ddsdde(6,6)
real(rp), intent(out) :: gpstr(3,3)
real(rp), intent(out) :: gpdds(3,3,3,3)

real(rp) :: vostr(6), voddsdde(6,6)

!-------------------------------------------------------------------
!
! Stress tensor
!
!-------------------------------------------------------------------
!
! [11, 22, 33, 12, 13, 23] UMAT Abaqus
! [11, 22, 33, 23, 13, 12] Alya
!
! Alya Abaqus
vostr(1) = stress(1)
vostr(2) = stress(2)
vostr(3) = stress(3)
vostr(4) = stress(6)
vostr(5) = stress(5)
vostr(6) = stress(4)

! From Voigt notation to tensorial notation


call SM_Voigt2Tensor_2nd(SM_V2T_KINETIC, vostr(:), gpstr(:,:))

!-------------------------------------------------------------------
!
! Second eleasticity tensor
!
!-------------------------------------------------------------------
!
! [11, 22, 33, 12, 13, 23] UMAT Abaqus
! [11, 22, 33, 23, 13, 12] Alya
!
! Alya Abaqus
voddsdde(1,1) = ddsdde(1,1)
voddsdde(1,2) = ddsdde(1,2)
voddsdde(1,3) = ddsdde(1,3)
voddsdde(1,4) = ddsdde(1,6)
voddsdde(1,5) = ddsdde(1,5)
voddsdde(1,6) = ddsdde(1,4)

voddsdde(2,1) = ddsdde(2,1)
voddsdde(2,2) = ddsdde(2,2)
voddsdde(2,3) = ddsdde(2,3)
voddsdde(2,4) = ddsdde(2,6)
voddsdde(2,5) = ddsdde(2,5)
voddsdde(2,6) = ddsdde(2,4)

voddsdde(3,1) = ddsdde(3,1)
voddsdde(3,2) = ddsdde(3,2)
voddsdde(3,3) = ddsdde(3,3)
voddsdde(3,4) = ddsdde(3,6)
voddsdde(3,5) = ddsdde(3,5)
voddsdde(3,6) = ddsdde(3,4)

voddsdde(4,1) = ddsdde(6,1)
voddsdde(4,2) = ddsdde(6,2)
voddsdde(4,3) = ddsdde(6,3)
voddsdde(4,4) = ddsdde(6,6)
voddsdde(4,5) = ddsdde(6,5)
voddsdde(4,6) = ddsdde(6,4)

voddsdde(5,1) = ddsdde(5,1)
voddsdde(5,2) = ddsdde(5,2)
voddsdde(5,3) = ddsdde(5,3)
voddsdde(5,4) = ddsdde(5,6)
voddsdde(5,5) = ddsdde(5,5)
voddsdde(5,6) = ddsdde(5,4)

voddsdde(6,1) = ddsdde(4,1)
voddsdde(6,2) = ddsdde(4,2)
voddsdde(6,3) = ddsdde(4,3)
voddsdde(6,4) = ddsdde(4,6)
voddsdde(6,5) = ddsdde(4,5)
voddsdde(6,6) = ddsdde(4,4)

! From Voigt notation to tensorial notation


call SM_tensor_to_voigt_fourth(3_ip, 1_ip, gpdds(:,:,:,:), voddsdde(:,:))

end subroutine sld_abaqus2alya

subroutine
sld_stress_model_155(pgaus,pmate,gpgdi,gpeps,ielem,gpstr,gpdds,gppio,gptmo)

use def_master, only : ITER_K_STATE, TIME_N_STATE


use def_solidz, only : parco_sld, lawco_sld
use def_solidz, only : svegm_sld, celen_sld
use mod_sld_stress_model_comput, only : SM_Tensor2Voigt_2nd, SM_T2V_KINEMATIC

implicit none

integer(ip), intent(in) :: pgaus !< No. gauss points


integer(ip), intent(in) :: pmate !< Material code
integer(ip), intent(in) :: ielem !< Current element
number
real(rp), intent(in) :: gpgdi(3,3,pgaus)
real(rp), intent(in) :: gpeps(3,3,pgaus) !< Strain tensor
real(rp), intent(out) :: gpstr(3,3,pgaus) !< Stress in tensor
form
real(rp), intent(out) :: gpdds(3,3,3,3,pgaus) !< Elasticity tensor
in tensor form
real(rp), intent(out) :: gppio(3,3,pgaus)
real(rp), intent(out) :: gptmo(3,3,3,3,pgaus)

integer(ip), parameter :: ndi=3_ip !


integer(ip), parameter :: nshr=3_ip !
integer(ip), parameter :: NTENS=6_ip !
integer(ip), parameter :: NPROPS=8_ip ! Number of user-defined materials
properties
integer(ip), parameter :: NSTATV=22_ip ! Number of user-defined state
variables 10 + 6 stresses

real(rp) :: STRAN(NTENS)
real(rp) :: DSTRAN(NTENS)
real(rp) :: STRESS(NTENS)
real(rp) :: STATEV(NSTATV)
real(rp) :: DDSDDE(NTENS,NTENS) ! Tangent matrix
real(rp) :: PROPS(NPROPS) ! Material properties
real(rp) :: CELENT ! Characteristic element length
integer(ip) :: lawco
!
! Others
!
integer(ip) :: igaus
real(rp) :: voeps(NTENS)

PROPS(1:NPROPS) = parco_sld(1:NPROPS,pmate)
CELENT = celen_sld(ielem)
lawco = lawco_sld(pmate)

do igaus = 1,pgaus
!
! Initialization
!
gpstr(:,:,igaus) = 0.0_rp
gpdds(:,:,:,:,igaus) = 0.0_rp
gppio(:,:,igaus) = 0.0_rp
gptmo(:,:,:,:,igaus) = 0.0_rp

!-------------------------------------------------------------------
!
! Strain tensor
!
!-------------------------------------------------------------------

call SM_Tensor2Voigt_2nd(SM_T2V_KINEMATIC, gpeps(:,:,igaus), voeps(:))


!
! Recover sdvs and stresses & strains
!
STATEV(1:NSTATV) = svegm_sld(ielem) % a(1:NSTATV,igaus,TIME_N_STATE)
STRESS(1:6) = svegm_sld(ielem) % a(11:16, igaus,TIME_N_STATE) ! In
Abaqus ordering (Stress elastic)
STRAN(1:6) = svegm_sld(ielem) % a(17:22, igaus,TIME_N_STATE) ! In
Abaqus ordering (Total previous strain)
!
! Compute total strain increment
!
! Strain increment (Total - previous) Ok!!!
! Abaqus Alya Abaqus
DSTRAN(1) = voeps(1) - STRAN(1) !11
DSTRAN(2) = voeps(2) - STRAN(2) !22
DSTRAN(3) = voeps(3) - STRAN(3) !33
DSTRAN(4) = voeps(6) - STRAN(4) !12
DSTRAN(5) = voeps(5) - STRAN(5) !13
DSTRAN(6) = voeps(4) - STRAN(6) !23

!-------------------------------------------------------------------
!
! UMAT: Effective stress tensor and Elasticiy tensor (ABAQUS)
!
!-------------------------------------------------------------------
call umat(STRESS, STATEV, DDSDDE, &
STRAN, DSTRAN, NDI, NSHR, NTENS, &
NSTATV, lawco, PROPS, NPROPS, &
CELENT)

!-------------------------------------------------------------------
!
! Stress and tangent convetion to alya
!
!-------------------------------------------------------------------

!call sld_abaqus2alya(STRESS(:), DDSDDE(:,:), gpstr(:,:,igaus),


gpdds(:,:,:,:,igaus))

!-------------------------------------------------------------------
!
! Stress and Tangen transformation (
! [Ref: Lucarni & Segurado, Computational Mechanics 2018,
https://doi.org/10.48550/arXiv.1806.10599]
!
!-------------------------------------------------------------------

call Tau2Piola(gpgdi(:,:,igaus), STRESS, DDSDDE, gppio(:,:,igaus),


gptmo(:,:,:,:,igaus))

!-------------------------------------------------------------------
!
! Store state variables
!
!-------------------------------------------------------------------

svegm_sld(ielem) % a(1:NSTATV, igaus,ITER_K_STATE) = STATEV(1:NSTATV)


svegm_sld(ielem) % a(11:16,igaus,ITER_K_STATE) = STRESS(1:6)
! Stress using Abaqus ordering
svegm_sld(ielem) % a(17:22,igaus,ITER_K_STATE) = STRAN(1:6) +
DSTRAN(1:6) ! Total strain using Abaqus ordering
end do

end subroutine sld_stress_model_155

end module mod_sld_stress_model_155

You might also like