Hi everybody,
I have written a script that evaluates a non-linear function feta
over a 2D domain. The function returns eta
that depends on other 2D fields (Exx, Eyy, Exy
). I try to compute the gradient of eta
w.r.t Exx, Eyy, Exy
et each cell of the domain using ForwardDiff (function feta_grad
). The function feta
itself is not trivial as it requires an inner non-linear iteration to compute eta
.
I have managed to make a MWE which I think can be optimized. It now allocates quite some memory on the way as both feta
and feta_grad
allocate memory. I have tried to make a non-allocating version of feta
but this is where I struggle. Indeed, parsing āscalarā arguments (here, for example eta[i,j]
) to a non-allocating version of feta
does not result in the modification of the value. The problem is likely related to this topic.
Iāve also tried to accelerate the evaluation by using LoopVectorization, but this gave me trouble. However this is most likely because of the if
statement contained within the function evaluation.
Would anyone have advices on how to optimize/make non-allocating version of the MWE below?
Thanks and cheers!
using ForwardDiff, LoopVectorization, Statistics
# Global variables
Ebg = -1.0; eta0 = 1.0; n = 3.0; G = 1.0; dt = 1.0
# Visco-elastic power law rheology
function feta(x::Vector{<:Real})
Eii = sqrt( 0.5*(x[1]^2 + x[2]^2) + x[3]^2)
C = (2eta0)^(-1)
eta = eta0*Eii^(1/n-1)
for it=1:10 # inner Newton iteration
Tii = 2eta*Eii
Eiiv = C*Tii^n
r = Eii - Tii/(2G*dt) - Eiiv
# if (abs(r)<1e-9) break; end # If statement does not work in LoopVectorization
drdeta = -Eii./(G.*dt) - Eiiv.*n./eta
eta -= r/drdeta
end
return eta
end
feta(Exx::Real,Eyy::Real,Exy::Real) = feta([Exx,Eyy,Exy]) # use multiple dispatch to make it work with the desired argument list
feta_grad(feta,x,y,z) = ForwardDiff.gradient(feta,[x,y,z]) # construct gradient function for feta()
# Setup
nx, ny = 100, 100
eta = 0.0*ones(Float64,nx,ny)
Exx, Eyy, Exy = Ebg.*ones(Float64,nx,ny), -Ebg.*ones(Float64,nx,ny), 0.2*Ebg.*ones(Float64,nx,ny)
detadExx, detadEyy, detadExy = zeros(Float64,nx,ny), zeros(Float64,nx,ny), zeros(Float64,nx,ny)
# Loop through all cells and evaluate
@time for j=1:ny
for i=1:nx
eta[i,j] = feta(Exx[i,j],Eyy[i,j],Exy[i,j])
detadExx[i,j], detadEyy[i,j], detadExy[i,j] = feta_grad(feta,Exx[i,j],Eyy[i,j],Exy[i,j])
end
end
# Check numbers
println( "eta = ", mean(eta) )
println( "detadExx = ", mean(detadExx) )
println( "detadEyy = ", mean(detadEyy) )
println( "detadExy = ", mean(detadExy) )