Skip to content

Commit

Permalink
Merge pull request #44 from zjwegert/nl_with_jac
Browse files Browse the repository at this point in the history
Allow user to pass analytic jacobian, test script provided
  • Loading branch information
zjwegert authored May 14, 2024
2 parents 9b1d0ff + 1417981 commit 5ac2ac9
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 8 deletions.
20 changes: 12 additions & 8 deletions src/ChainRules.jl
Original file line number Diff line number Diff line change
Expand Up @@ -575,14 +575,19 @@ struct NonlinearFEStateMap{A,B,C,D,E,F} <: AbstractFEStateMap
"""
function NonlinearFEStateMap(
res::Function,U,V,V_φ,U_reg,φh,dΩ...;
jac = nothing,
assem_U = SparseMatrixAssembler(U,V),
assem_adjoint = SparseMatrixAssembler(V,U),
assem_deriv = SparseMatrixAssembler(U_reg,U_reg),
nls::NonlinearSolver = NewtonSolver(LUSolver();maxiter=50,rtol=1.e-8,verbose=true),
adjoint_ls::LinearSolver = LUSolver()
)
res = IntegrandWithMeasure(res,dΩ)
jac = (u,du,dv,φh) -> jacobian(res,[u,dv,φh],1)
if isnothing(jac)
jacf = (u,du,v,φh) -> jacobian(res,[u,v,φh],1)
else
jacf = (u,du,v,φh) -> jac(u,du,v,φh,dΩ...)
end
spaces = (U,V,V_φ,U_reg)

## Pullback cache
Expand All @@ -594,21 +599,20 @@ struct NonlinearFEStateMap{A,B,C,D,E,F} <: AbstractFEStateMap
## Forward cache
x = zero_free_values(U)
_res(u,v) = res(u,v,φh)
_jac(u,du,dv) = jac(u,du,dv,φh)
_jac(u,du,v) = jacf(u,du,v,φh)
op = get_algebraic_operator(FEOperator(_res,_jac,U,V,assem_U))
nls_cache = instantiate_caches(x,nls,op)
fwd_caches = (nls,nls_cache,x,assem_U)

## Adjoint cache
_jac_adj(du,dv) = jac(uhd,du,dv,φh)
_jac_adj(du,v) = jacf(uhd,du,v,φh)
adjoint_K = assemble_adjoint_matrix(_jac_adj,assem_adjoint,U,V)
adjoint_x = allocate_in_domain(adjoint_K); fill!(adjoint_x,zero(eltype(adjoint_x)))
adjoint_ns = numerical_setup(symbolic_setup(adjoint_ls,adjoint_K),adjoint_K)
adj_caches = (adjoint_ns,adjoint_K,adjoint_x,assem_adjoint)

A, B, C = typeof(res), typeof(jac), typeof(spaces)
A, B, C = typeof(res), typeof(jacf), typeof(spaces)
D, E, F = typeof(plb_caches), typeof(fwd_caches), typeof(adj_caches)
return new{A,B,C,D,E,F}(res,jac,spaces,plb_caches,fwd_caches,adj_caches)
return new{A,B,C,D,E,F}(res,jacf,spaces,plb_caches,fwd_caches,adj_caches)
end
end

Expand All @@ -622,7 +626,7 @@ function forward_solve!(φ_to_u::NonlinearFEStateMap,φh)
nls, nls_cache, x, assem_U = φ_to_u.fwd_caches

res(u,v) = φ_to_u.res(u,v,φh)
jac(u,du,dv) = φ_to_u.jac(u,du,dv,φh)
jac(u,du,v) = φ_to_u.jac(u,du,v,φh)
op = get_algebraic_operator(FEOperator(res,jac,U,V,assem_U))
solve!(x,nls,op,nls_cache)
return x
Expand All @@ -636,7 +640,7 @@ end
function update_adjoint_caches!(φ_to_u::NonlinearFEStateMap,uh,φh)
adjoint_ns, adjoint_K, _, assem_adjoint = φ_to_u.adj_caches
U, V, _, _ = φ_to_u.spaces
jac(du,dv) = φ_to_u.jac(uh,du,dv,φh)
jac(du,v) = φ_to_u.jac(uh,du,v,φh)
assemble_adjoint_matrix!(jac,adjoint_K,assem_adjoint,U,V)
numerical_setup!(adjoint_ns,adjoint_K)
return φ_to_u.adj_caches
Expand Down
121 changes: 121 additions & 0 deletions test/seq/NeohookAnalyticJacALMTests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
module NeohookAnalyticJacALMTests
using Test

using Gridap, GridapTopOpt

"""
(Serial) Minimum hyperelastic (neohookean) compliance with augmented Lagrangian method in 2D.
"""
function main()
## Parameters
order = 1
xmax=ymax=1.0
prop_Γ_N = 0.2
dom = (0,xmax,0,ymax)
el_size = (20,20)
γ = 0.1
γ_reinit = 0.5
max_steps = floor(Int,order*minimum(el_size)/10)
tol = 1/(5order^2)/minimum(el_size)
η_coeff = 2
α_coeff = 4max_steps*γ
vf = 0.6

## FE Setup
model = CartesianDiscreteModel(dom,el_size);
el_Δ = get_el_Δ(model)
f_Γ_D(x) = (x[1] 0.0)
f_Γ_N(x) = (x[1] xmax && ymax/2-ymax*prop_Γ_N/2 - eps() <= x[2] <= ymax/2+ymax*prop_Γ_N/2 + eps())
update_labels!(1,model,f_Γ_D,"Gamma_D")
update_labels!(2,model,f_Γ_N,"Gamma_N")

## Triangulations and measures
Ω = Triangulation(model)
Γ_N = BoundaryTriangulation(model,tags="Gamma_N")
= Measure(Ω,2*order)
dΓ_N = Measure(Γ_N,2*order)
vol_D = sum((1)dΩ)

## Spaces
reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order)
reffe_scalar = ReferenceFE(lagrangian,Float64,order)
V = TestFESpace(model,reffe;dirichlet_tags=["Gamma_D"])
U = TrialFESpace(V,VectorValue(0.0,0.0))
V_φ = TestFESpace(model,reffe_scalar)
V_reg = TestFESpace(model,reffe_scalar;dirichlet_tags=["Gamma_N"])
U_reg = TrialFESpace(V_reg,0)

## Create FE functions
φh = interpolate(initial_lsf(4,0.2),V_φ)

## Interpolation and weak form
interp = SmoothErsatzMaterialInterpolation= η_coeff*maximum(el_Δ))
I,H,DH,ρ = interp.I,interp.H,interp.DH,interp.ρ

## Material properties
_E = 1000
ν = 0.3
μ, λ = _E/(2*(1 + ν)), _E*ν/((1 + ν)*(1 - ν))
g = VectorValue(0,-20)

## Neohookean hyperelastic material
# Deformation gradient
F(∇u) = one(∇u) + ∇u'
J(F) = sqrt(det(C(F)))

# Derivative of green Strain
dE(∇du,∇u) = 0.5*( ∇duF(∇u) + (∇duF(∇u))' )

# Right Caughy-green deformation tensor
C(F) = (F')F

# Constitutive law (Neo hookean)
function S(∇u)
Cinv = inv(C(F(∇u)))
μ*(one(∇u)-Cinv) + λ*log(J(F(∇u)))*Cinv
end

function dS(∇du,∇u)
Cinv = inv(C(F(∇u)))
_dE = dE(∇du,∇u)
λ*(Cinv_dE)*Cinv + 2*-λ*log(J(F(∇u))))*Cinv_dE(Cinv')
end

# Cauchy stress tensor and residual
σ(∇u) = (1.0/J(F(∇u)))*F(∇u)S(∇u)(F(∇u))'
res(u,v,φ,dΩ,dΓ_N) = ( (I φ)*((dE((v),(u))) (S(u))) )*- (gv)dΓ_N
jac_mat(u,du,v,φ,dΩ,dΓ_N) = ( (I φ)*(dE((v),(u))) (dS((du),(u))) )*
jac_geo(u,du,v,φ,dΩ,dΓ_N) = ( (I φ)*(v) ( (S(u))(du) ) )*
jac(u,du,v,φ,dΩ,dΓ_N) = jac_mat(u,du,v,φ,dΩ,dΓ_N) + jac_geo(u,du,v,φ,dΩ,dΓ_N)

## Optimisation functionals
J(u,φ,dΩ,dΓ_N) = ((I φ)*((dE((u),(u))) (S(u))))dΩ
Vol(u,φ,dΩ,dΓ_N) = (((ρ φ) - vf)/vol_D)dΩ;
dVol(q,u,φ,dΩ,dΓ_N) = (-1/vol_D*q*(DH φ)*(norm (φ)))dΩ

## Finite difference solver and level set function
ls_evo = HamiltonJacobiEvolution(FirstOrderStencil(2,Float64),model,V_φ,tol,max_steps)

## Setup solver and FE operators
state_map = NonlinearFEStateMap(res,U,V,V_φ,U_reg,φh,dΩ,dΓ_N;jac)
pcfs = PDEConstrainedFunctionals(J,[Vol],state_map,analytic_dC=[dVol])

## Hilbertian extension-regularisation problems
α = α_coeff*maximum(el_Δ)
a_hilb(p,q) =^2*(p)(q) + p*q)dΩ
vel_ext = VelocityExtension(a_hilb,U_reg,V_reg)

## Optimiser
optimiser = AugmentedLagrangian(pcfs,ls_evo,vel_ext,φh;
γ,γ_reinit,verbose=true,constraint_names=[:Vol])

# Do a few iterations
vars, state = iterate(optimiser)
vars, state = iterate(optimiser,state)
true
end

# Test that these run successfully
@test main()

end # module

0 comments on commit 5ac2ac9

Please sign in to comment.