p-Laplacian

Problem statement
Find the scalar-field $u$ such that
\[\left\lbrace \begin{aligned} -\nabla \cdot \sigma(u) = f\ &\text{in}\ \Omega,\\ u = -1 \ &\text{on} \ \Gamma_0,\\ u = 1 \ &\text{on} \ \Gamma_1,\\ \sigma(u)\cdot n = 0 \ &\text{elsewhere on} \ \partial\Omega, \end{aligned} \right.\]
with $\sigma(u) = |\nabla u|^{p-2} \ \nabla u$ and $p>2$. The vector field $n$ is the outwards unit normal vector to $\partial\Omega$. The computational domains are defined in the mesh file model.msh. The domain $\Omega$ is represented by the 3D faces in this mesh. The domain $\Gamma_0$ is represented by the physical group named "sides" and $\Gamma_1$ is the union of the physical groups named "circle", "triangle", and "square".
Numerical scheme
We discretize the problem with a space $V$ with piece-wise continuous Lagrangian basis functions. For this formulation, the nonlinear weak form reads: find $u\in V_g$ such that $[r(u)](v) = 0$ for all $v\in V_0$. The auxiliary spaces $V_g$ and $V_0$ are the subsets of $V$ that fulfill the Dirichlet boundary condition $g$ and $0$ on $\partial\Omega$ respectively.
The weak residual $r(u)$ evaluated at a function $u\in V_g$ is the linear form defined as
\[[r(u)](v) \doteq \int_\Omega \nabla v \cdot \left( |\nabla u|^{p-2}\ \nabla u \right) \ {\rm d}\Omega - \int_\Omega v\ f \ {\rm d}\Omega.\]
In order to solve this nonlinear weak equation, we consider a Newton-Raphson method, which is associated with a linearization of the problem in an arbitrary direction $\delta u\in V_0$, namely $[r(u+\delta u)](v)\approx [r(u)](v) + [j(u)](\delta u,v)$. In previous formula, $j(u)$ is the Jacobian evaluated at $u\in V_g$, which is the bilinear form
\[[j(u)](\delta u,v) = \int_\Omega \nabla v \cdot \left( |\nabla u|^{p-2}\ \nabla \delta u \right) \ {\rm d}\Omega + (p-2) \int_\Omega \nabla v \cdot \left( |\nabla u|^{p-4} (\nabla u \cdot \nabla \delta u) \nabla u \right) \ {\rm d}\Omega.\]
Implementation
using LinearAlgebra
import Gmsh
import GalerkinToolkit as GT
import PartitionedSolvers as PS
import NonlinearSolve
import ForwardDiff
import GLMakie as Makie
#Read and visualize the mesh
assets_dir = normpath(joinpath(@__DIR__,"..","..","..","assets"))
msh_file = joinpath(assets_dir,"model.msh")
mesh = GT.mesh_from_msh(msh_file)
#Define domains
dirichlet_names = ["sides","circle", "triangle", "square"]
Ω = GT.interior(mesh)
Γd = GT.boundary(mesh;group_names=dirichlet_names)
#Define forcing data
g = GT.analytical_field(Γd;piecewise=true) do x,name
if name == "sides"
-1
else
1
end
end
#Define the interpolation space
k = 1
V = GT.lagrange_space(Ω,k;dirichlet_boundary=Γd)
#Interpolate Dirichlet values
T = Float64
uh = GT.rand_field(T,V)
GT.interpolate_dirichlet!(g,uh)
#Define numerical integration
degree = 2*k
dΩ = GT.measure(Ω,degree)
#Define weak form.
∇ = ForwardDiff.gradient
q = 3
flux(∇u) = norm(∇u)^(q-2) * ∇u
dflux(∇du,∇u) = (q-2)*norm(∇u)^(q-4)*(∇u⋅∇du)*∇u+norm(∇u)^(q-2)*∇du
r = u -> v -> GT.∫( x-> ∇(v,x)⋅GT.call(flux,∇(u,x)), dΩ)
j = u -> (du,v) -> GT.∫( x-> ∇(v,x)⋅GT.call(dflux,∇(du,x),∇(u,x)) , dΩ)
#Define non-linear problem
p = GT.SciMLBase_NonlinearProblem(uh,r,j)
#Solve it
sol = NonlinearSolve.solve(p;show_trace=Val(true))
@assert sol.retcode == NonlinearSolve.ReturnCode.Success
#Get the FE solution object
uh = GT.solution_field(uh,sol)
#Visualize the solution
fig = Makie.Figure()
elevation = 0.24π
azimuth = -0.55π
aspect = :data
ax = Makie.Axis3(fig[1,1];aspect,elevation,azimuth)
Makie.hidespines!(ax)
Makie.hidedecorations!(ax)
GT.makie_surfaces!(Ω;color=uh)
Algorithm: NewtonRaphson(
descent = NewtonDescent(),
autodiff = AutoForwardDiff(),
vjp_autodiff = AutoFiniteDiff(
fdtype = Val{:forward}(),
fdjtype = Val{:forward}(),
fdhtype = Val{:hcentral}(),
dir = true
),
jvp_autodiff = AutoForwardDiff(),
concrete_jac = Val{false}()
)
---- ------------- -----------
Iter f(u) inf-norm Step 2-norm
---- ------------- -----------
0 1.39583318e+01 NaN
1 3.68589549e+00 1.73491917e+01
2 8.48044957e-01 7.99011082e+00
3 1.94112321e-01 3.17048964e+00
4 3.74052453e-02 9.88370460e-01
5 1.04883862e-02 2.66062158e-01
6 1.02827848e-03 5.92275612e-02
7 2.13740880e-05 7.77122795e-03
8 4.70763148e-08 2.47623000e-04
9 6.75347954e-13 5.77834440e-07
10 3.74700271e-16 8.20941104e-12
Final 3.74700271e-16
----------------------Building the algebraic non-linear problem explicitly
In this other version, we explicitly build the algebraic residual and Jacobian (functions that take plain Julia vectors) and build a algebraic non-linear problem from them.
import SciMLBase
#Initial guess
x = rand(T,GT.num_free_dofs(V))
GT.solution_field!(uh,x)
#Initial residual and Jacobian
reuse = Val(true)
parameters = (uh,)
b,residual_cache = GT.assemble_vector(r(uh),T,V;parameters,reuse)
A,jacobian_cache = GT.assemble_matrix(j(uh),T,V,V;parameters,reuse)
#Algebraic residual and Jacobian functions
function f(dx,x,p)
GT.solution_field!(uh,x)
GT.update_vector!(dx,residual_cache;parameters)
dx
end
function jac(J,x,p)
GT.solution_field!(uh,x)
GT.update_matrix!(J,jacobian_cache;parameters)
J
end
#Build the nonlinear problem
jac_prototype = A
nlfun = SciMLBase.NonlinearFunction(f;jac,jac_prototype)
p = SciMLBase.NonlinearProblem(nlfun,x)
#Solve it
sol = NonlinearSolve.solve(p;show_trace=Val(true))
@assert sol.retcode == NonlinearSolve.ReturnCode.Success
#Get the FE solution object
x = sol.u
GT.solution_field!(uh,x)
#Visualize the solution
fig = Makie.Figure()
elevation = 0.24π
azimuth = -0.55π
aspect = :data
ax = Makie.Axis3(fig[1,1];aspect,elevation,azimuth)
Makie.hidespines!(ax)
Makie.hidedecorations!(ax)
GT.makie_surfaces!(Ω;color=uh)
Algorithm: NewtonRaphson(
descent = NewtonDescent(),
autodiff = AutoForwardDiff(),
vjp_autodiff = AutoFiniteDiff(
fdtype = Val{:forward}(),
fdjtype = Val{:forward}(),
fdhtype = Val{:hcentral}(),
dir = true
),
jvp_autodiff = AutoForwardDiff(),
concrete_jac = Val{false}()
)
---- ------------- -----------
Iter f(u) inf-norm Step 2-norm
---- ------------- -----------
0 1.29789381e+01 0.00000000e+00
1 3.31142161e+00 1.67941775e+01
2 8.35426073e-01 7.79004514e+00
3 1.80554999e-01 3.03471826e+00
4 2.62954299e-02 1.06751596e+00
5 4.53878668e-03 2.33322143e-01
6 9.01689046e-04 5.65881579e-02
7 9.25802740e-05 1.12497992e-02
8 2.13801569e-06 1.53667383e-03
9 3.19228885e-09 5.20433646e-05
10 8.32000484e-15 7.11303674e-08
Final 8.32000484e-15
----------------------This page was generated using Literate.jl.