Skip to content

Constitutive equation ​

In the more general case, JustRelax.jl implements a elasto-visco-elastoplastic rheology. Where the constitutive equation is:

ε˙=ε˙viscous+ε˙elastic+ε˙plastic

or

ε˙=12ηeffτ+12GDτDt+λ˙∂Q∂τII

where ηeff is the effective viscosity, G is the elastic shear modulus, λ˙ is the plastic multiplier, and Q is the plastic flow potential is:

Q=τII−psin⁡ψ

where ψ is the dilation angle.

Effective viscosity ​

The effective viscosity of a non-Newtonian Maxwell body is defined as:

ηeff=11ηdiff+1ηdisl

where ηdiff and ηdisl are the diffusion and dislocation creep viscosities. These are computed from their respective strain rate equations:

ε˙IIdiff=AdiffτIIndiffdpfH2Ordiffexp⁡(−Ediff+PVdiffRT)ε˙IIdisl=AdislτIIndislfH2Ordislexp⁡(−Edisl+PVdislRT)

where A material specific parameter, n is the stress powerlaw exponent, p is the negative defined grain size exponent, f is the water fugacity, r is the water fugacity exponent, E is the activation energy, PV is the activation volume, and R is the universal gas constant.

Elastic stress ​

The elastic stress is rotated on the particles level, and it is done using Euler-Rodrigues rotation method, with the following steps:

  1. Compute unit rotation axis
α=ω⋅un=αI1ω

where u is a unit vector of length Rn.

  1. Integrate rotation angle
θ=α2Δt
  1. Euler-Rodrigues rotation matrix
c=nsin⁡θR1=[cos⁡θsin⁡θ−c3c2c3cos⁡θsin⁡θ−c1−c2c1cos⁡θsin⁡θ]R2=(1−cos⁡θ)nnTR=R1+R2
  1. Rotate stress tensor
τ⋆=RτRT

Plastic formulation ​

JustRelax.jl implements the regularised plasticity model from Duretz et al 2021. In this formulation, the yield function is given by

F=τII−(Psin⁡ϕ+Ccos⁡ϕ+λ˙ηreg)≥0

where ηreg is a regularization term and

λ˙=Ftrialη+ηreg+KΔtsin⁡ψsin⁡ϕ

Note that since we are using an iterative method to solve the APT Stokes equation, the non-linearities are dealt by the iterative scheme. Othwersie, one would need to solve a non-linear problem to compute λ˙, which requires to compute ∂F∂λ˙

Selecting the constitutive model in JustRelax.jl ​

All the local calculations corresponding to the effective rheology are implemented in GeoParams.jl. The composite rheology is implemented using the CompositeRheology object. An example of how to set up the a visco-elasto-viscoplastic rheology is shown below:

julia
# elasticity
el    = ConstantElasticity(;
    G = 40e9, # shear modulus [Pa]
    ν = 0.45, # Poisson coefficient
)
# Olivine dislocation law from Hirth and Kohlstedt 2003
disl_wet_olivine  = SetDislocationCreep(Dislocation.wet_olivine1_Hirth_2003)
# Olivine diffusion law from Hirth and Kohlstedt 2003
diff_wet_olivine  = SetDiffusionCreep(Diffusion.wet_olivine_Hirth_2003)
# plasticity
ϕ     = 30   # friction angle
Ψ     = 5    # dilation angle
C     = 1e6  # cohesion [Pa]
η_reg = 1e16 # viscosity regularization term [Pa s]
pl    = DruckerPrager_regularised(; C = C, ϕ = ϕ, η_vp=η_reg, Ψ=Ψ)
# composite rheology
rheology = CompositeRheology(
    (el, disl_wet_olivine, diff_wet_olivine, pl)
)

rheology then needs to be passed into a MaterialParams object with the help of SetMaterialParams:

julia
rheology = (
    SetMaterialParams(;
        Phase             = 1,
        CompositeRheology = rheology,
        # other material properties here
    ),
)

Multiple rheology phases ​

It is common in geodynamic models to have multiple rheology phases. In this case, we just need to build a tuple containing every single material phase properties:

julia
rheology = (
    SetMaterialParams(;
        Phase             = 1,
        CompositeRheology = rheology_one,
        # other material properties here
    ),
        SetMaterialParams(;
        Phase             = 2,
        CompositeRheology = rheology_two,
        # other material properties here
    ),
)

Computing the effective viscosity ​

The effective viscosity is computed internally during the Stokes solver. However, it can also be computed externally with the compute_viscosity! function as follows:

julia
# Rheology
args             = (T=T, P=P, dt = dt)
viscosity_cutoff = (1e18, 1e23)
compute_viscosity!(stokes, phase_ratios, args, rheology, viscosity_cutoff)

where T and P are the temperature and pressure fields defined at the cell centers, dt is the time step, and phase_ratios is an object containing the phase ratios corresponding to each material phase, of each cell.

Elastic stress rotation ​

The elastic stress rotation is done on the particles.

  1. Allocate stress tensor on the particles:
julia
pτ = StressParticles(particles)
  1. Since JustPIC.jl requires the fields to be defined at the cell vertices, we need to allocate a couple of buffer arrays where we will interpolate the normal compononents of the stress tensor:
julia
τxx_v = @zeros(ni.+1...)
τyy_v = @zeros(ni.+1...)
  1. During time stepping:
julia
# 1. interpolate stress back to the grid
stress2grid!(stokes, pτ, particles)
# 2. solve Stokes equations....
#
# 3. rotate stresses
rotate_stress!(pτ, stokes, particles, dt)
# 4. advection step
    # advect particles in space
advection!(particles, RungeKutta2(), @velocity(stokes), dt)
    # advect particles in memory
move_particles!(particles, particle_args)
    # check if we need to inject particles
    # need stresses on the vertices for injection purposes
center2vertex!(τxx_v, stokes.τ.xx)
center2vertex!(τyy_v, stokes.τ.yy)
inject_particles_phase!(
        particles,
        pPhases,
        pτ,
        (τxx_v, τyy_v, stokes.τ.xy, stokes.ω.xy)
)

Note that rotate_stress! rotates the stress tensor using the Euler-Rodrigues rotation matrix.