In [ ]:
using PyPlot, Compose
using LujiaLt.FEM
In [ ]:
# implement a radial mesh
# we only need to produce the point
# and let the delaunay triangulation create the elements
function Xsquare(N)
x = linspace(-1, 1, N)
o = ones(N)
x, y = (x * o')[:], (o * x')[:]
return [x'; y']
end
# create the nodes for the triangulation
Ntest = 12
X = Xsquare(Ntest)
# plot(X[1,:], X[2,:], "b.");
# we also need something that will give us the
# interior (free) nodes
free_nodes(X) = find( maxabs(X, 1) .< 1-1e-10 );
In [ ]:
# create a triangulation
tri = Triangulation(X)
FEM.plot(tri; width=10cm, xradius=0.02, lwidth=0.5);
In [ ]:
# check how many triangles we have
println("number of triangles = ", nT(tri))
println("we should have ", 2 * (Ntest-1)^2)
if nT(tri) == 2 * (Ntest-1)^2
println("""=> this is great: it means that no thin triangles are
created on the boundary due to numerical round-off!""")
else
println("something went wrong: please file an issue!")
end
In [ ]:
# assembly of P1-laplacian
function P1_laplacian(tri)
# initialise triplet format
I = Int[]; J = Int[]; V = Float64[]
# initialise r-h-s
F = zeros(nX(tri))
# assembly loop
for el in elements(tri)
# element stiffness matrix (el.B is the gradient operator)
Ael = el.vol * el.B * el.B'
# write into global stiffness matrix
for i = 1:3, j = 1:3
push!(I, el.t[i]); push!(J, el.t[j]); push!(V, Ael[i,j])
end
# r-h-s (force ≡ 1)
F[el.t] = el.vol / 3
end
return sparse(I, J, V), F
end
In [ ]:
# solve
tri = Triangulation(Xsquare(30))
A, b = P1_laplacian(tri)
u = zeros(nX(tri))
Ifree = free_nodes(tri.X)
u[Ifree] = A[Ifree, Ifree] \ b[Ifree];
# … and plot
PyPlot.plot_trisurf(tri.X[1,:][:], tri.X[2,:][:], u,
triangles=tri.T'-1,
cmap=ColorMap("inferno"), linewidth=0.5)
title("Success: this looks correct!")
In [ ]:
# specify the energy
W(F, p) = (0.01 + 1/p * sumabs2(F))^(p/2)
dW(F, p) = (0.01 + 1/p * sumabs2(F))^(p/2-1) * F
# u : dof vector
# tri : triangulation
# p : p parameter for p-laplacian
# u0 : dirichlet condition
# Ifree : free nodes
function plaplacian(u, tri, p, u0, Ifree)
@assert 1 < p < Inf
v = copy(u0)
v[Ifree] = u
E = 0.0
dE = zeros(nX(tri))
for el in elements(tri)
Du = el.B' * v[el.t]
E += el.vol * (W(Du, p) - mean(v[el.t]))
dE[el.t] += el.vol * (el.B * dW(Du, p) - ones(length(el.t))/length(el.t))
end
return E, dE[Ifree]
end
In [ ]:
# finite-difference test to make sure this is correctly implemented
import LujiaLt.Testing
tri = Triangulation(Xsquare(8))
A, b = P1_laplacian(tri)
u0 = zeros(nX(tri))
Ifree = free_nodes(tri.X)
p = 4
F = u -> plaplacian(u, tri, p, u0, Ifree)[1]
dF = u -> plaplacian(u, tri, p, u0, Ifree)[2]
LujiaLt.Testing.fdtest(F, dF, 0.1 * rand(length(Ifree)))
In [ ]:
#
import Optim
tri = Triangulation(Xsquare(30))
A, b = P1_laplacian(tri)
u0 = zeros(nX(tri))
Ifree = free_nodes(tri.X)
p = 8
E, dE = plaplacian(u0[Ifree], tri, p, u0, Ifree)
# unfortunately, Optim.jl doesn't allow the type of
# objective we just implemented, we need to do a
# silly hack - some work to do to fix this!
F = u -> plaplacian(u, tri, p, u0, Ifree)[1]
dF = u -> plaplacian(u, tri, p, u0, Ifree)[2]
dF! = (u, g) -> copy!( g, dF(u) )
obj = Optim.DifferentiableFunction(F, dF!)
# call Optim
results = Optim.optimize(obj, u0[Ifree],
method = Optim.ConjugateGradient(P = A[Ifree, Ifree]),
ftol = 1e-32, grtol = 1e-8)
u = copy(u0);
u[Ifree] = results.minimum
# plot result
PyPlot.plot_trisurf(tri.X[1,:][:], tri.X[2,:][:], u,
triangles=tri.T'-1,
cmap=ColorMap("viridis"), linewidth=0.5)
In [ ]: