I am currently trying to solve a minimization problem, and this is the paper I am referring to. Based on equation (3.14) from the paper, I attempted to store the first term on left-hand side and the right-hand side using numpy.
Below is my code. However, after summing the first term with the other terms, I am not sure how to apply the boundary conditions, which is the issue I am facing.
Or maybe the way I am storing things in numpy is incorrect.
Although the program can run and it seems fine in the case of p=2 (the linear case).
from fenics import *
from dolfin import *
from petsc4py import PETSc
import numpy as np
import matplotlib.pyplot as plt
import math
p = 4 # p-Laplace
pdeg = 1
size = 4
# p=2
mesh = RectangleMesh(Point(0, 0), Point(1, 1), size, size)
f = Expression(" 2*pow(pi,2)*sin(pi*x[0])*sin(pi*x[1])", degree=5,pi=math.pi)
uex = Expression(" sin(pi*x[0])*sin(pi*x[1])",degree=5,pi=math.pi)
qex = Expression((" pi*sin(pi*x[1])*cos(pi*x[0]) "," pi*sin(pi*x[0])*cos(pi*x[1]) "),degree=5,pi=math.pi)
sigmaex = Expression((" pi*sin(pi*x[1])*cos(pi*x[0]) "," pi*sin(pi*x[0])*cos(pi*x[1]) "),degree=5,pi=math.pi)
Coe = Constant(1.0)
# p=4
mesh = RectangleMesh(Point(0, 0), Point(1, 1), size, size)
uex = Expression(" sin(pi*x[0])*sin(pi*x[1])",degree=5,pi=math.pi)
qex = Expression((" pi*sin(pi*x[1])*cos(pi*x[0]) "," pi*sin(pi*x[0])*cos(pi*x[1]) "),degree=5,pi=math.pi)
Coe = Expression("pow((pow(pi,2)*pow(sin(pi*x[0]),2)*pow(cos(pi*x[1]),2) + pow(pi,2)*pow(sin(pi*x[1]),2)*pow(cos(pi*x[0]),2)),1.0)", degree=5,pi=math.pi)
sigmaex = Expression((" Coe*pi*sin(pi*x[1])*cos(pi*x[0]) "," Coe*pi*sin(pi*x[0])*cos(pi*x[1]) "),degree=5,pi=math.pi,Coe=Coe)
f = Expression(" (0.5*pow(pi,4.0)*(-cos(pi*(2*x[0] - 2*x[1])) - cos(pi*(2*x[0] + 2*x[1])) + 2) - 2.0*pow(pi,4)*pow(cos(pi*x[0]),2)*cos(2*pi*x[1]) - 2.0*pow(pi,4)*cos(2*pi*x[0])*pow(cos(pi*x[1]),2))*sin(pi*x[0])*sin(pi*x[1])", degree=5,pi=math.pi)
P1 = VectorElement("DG", triangle, pdeg)
P2 = VectorElement("DG", triangle, pdeg)
P3 = FiniteElement("DG", triangle, pdeg)
P1P2P3 = MixedElement([P1, P2, P3])
W = FunctionSpace(mesh, P1P2P3)
V1 = FunctionSpace(mesh, P1)
V2 = FunctionSpace(mesh, P2)
V3 = FunctionSpace(mesh, P3)
(q,sigma,u) = TrialFunctions(W)
(zeta,tau,v) = TestFunctions(W)
n = FacetNormal(mesh)
h = CellDiameter(mesh)
h_avg = (h('+') + h('-'))/2
# norm
def vecnorm(u):
absu = pow(inner(u,u),0.5)
return absu
def scalarnorm(u):
absu = pow(pow(u,2),0.5)
return absu
# DG discrete weak gradient operators
def Discrete_weak_gradient(v,g):
(q,sigma,uu) = TrialFunctions(W)
(zeta,tau,vv) = TestFunctions(W)
v = project(v,V3) # v function
g = project(g,V3) # g function
# # choose C12
C12 = Constant((1.0,0))
dot_product = inner(C12,n('+'))
sign = conditional(dot_product > 0, 1.0, -1.0)
bc = DirichletBC(W.sub(2), g, "on_boundary")
L = inner(q,zeta)*dx
R = -v*div(zeta)*dx + avg(v)*inner(jump(zeta),n('+'))*dS\
+ inner(0.5*sign,jump(v))*inner(jump(zeta),n('+'))*dS + g*inner(zeta,n)*ds
F = L - R
L = lhs(F)
R = rhs(F)
w = Function(W)
solve(L==R,w,bc)
(q,sigma,u) = w.split()
return q
# energy functional
def J(u,g,eta):
eta = Constant(eta)
Dwg_u_g = Discrete_weak_gradient(u,g)
Ju = 1/p*pow(vecnorm(Dwg_u_g),p)*dx\
+ 1/p*eta*pow(h_avg,1-p)*pow(vecnorm(jump(u,n)),p)*dS\
+ 1/p*eta*pow(h,1-p)*pow(scalarnorm(u-g),p)*ds - f*u*dx
return Ju
# nonlinear coefficient
def nonlinear(vec):
nonlinear = pow((vecnorm(vec)),p-2)*vec
return nonlinear
# calculate derivative of energy functional
def dJudv_value(u,g,v,eta,Dwg1,Dwg2): # v function
eta = Constant(eta)
nonlinear1 = nonlinear(Dwg1)
nonlinear2 = nonlinear((1/h_avg)*jump(u,n))
nonlinear3 = nonlinear((1/h)*(u-g)*n)
dJudv_value = inner(nonlinear1,Dwg2)*dx\
+ eta*inner(nonlinear2,jump(v,n))*dS\
+ eta*inner(nonlinear3,v*n)*ds - f*v*dx
return assemble(dJudv_value)
# derivative of energy functional
def dJudv_fn(u,g,v,eta): # v testfunction
eta = Constant(eta)
nonlinear2 = nonlinear((1/h_avg)*jump(u,n))
nonlinear3 = nonlinear((1/h)*(u-g)*n)
dJudv_fn = eta*inner(nonlinear2,jump(v,n))*dS\
+ eta*inner(nonlinear3,v*n)*ds - f*v*dx
return dJudv_fn
Amat = np.zeros((V3.dim(), V3.dim()))
bvec = np.zeros(V3.dim())
dofmap = V3.dofmap()
global_dofs = dofmap.dofs()
Dwg_phi_j_0_list = []
for j in range(V3.dim()):
phi_j = Function(V3)
phi_j.vector()[j] = 1
Dwg_phi_j_0_list.append(Discrete_weak_gradient(phi_j, Constant(0.0)))
print("Dimension V3: ",V3.dim())
# set boundary condition and collect boundary dofs
uD = project(uD,V3)
bc = DirichletBC(V3, uD , "on_boundary")
# boundary_dofs = list(set(bc.get_boundary_values().keys()))
eps = 1.0
tol = 1.0e-6
iter = 0
maxiter = 10
epsi = 1.0e-14 # avoid degeneracy
while eps > tol and iter < maxiter:
w = TrialFunction(V3)
v = TestFunction(V3)
alpha = 1.0
# Find the steepest direction
# The first term of LHS and RHS for p=4 (equation (3.14) )
Dwg_u0_g = Discrete_weak_gradient(u0,uD)
Dwg_u0_g_coe = nonlinear(Dwg_u0_g)
Dwg_u0_g_norm = pow(vecnorm(Dwg_u0_g),p-2)
for i in range(V3.dim()):
Dwg_phi_i_0 = Dwg_phi_j_0_list[i]
phivalue = assemble(inner(Dwg_u0_g_coe, Dwg_phi_i_0) * dx)
bvec[global_dofs[i]] = phivalue
for j in range(V3.dim()):
Dwg_phi_j_0 = Dwg_phi_j_0_list[j]
phi_ij_value = assemble((epsi + Dwg_u0_g_norm) * inner(Dwg_phi_i_0, Dwg_phi_j_0) * dx)
Amat[global_dofs[i], global_dofs[j]] = phi_ij_value
weighted = assemble(Constant(eta)*(1/h_avg) * (epsi + pow(vecnorm((1/h_avg)*jump(u0,n)),p-2) ) *inner(jump(w,n),jump(v,n))*dS\
+ Constant(eta)*(1/h)* (epsi + pow(vecnorm((1/h)*(u0-uD)),p-2) ) * w * v * ds)
Apetsc = as_backend_type(weighted).mat()
Apetsc = Apetsc.getValues(range(0, Apetsc.getSize()[0]), range(0, Apetsc.getSize()[1]))
Amat = Amat + Apetsc
dJudv = assemble(dJudv_fn(u0,uD,v,eta))
dJudv_vec = dJudv.get_local()
bvec = bvec + dJudv_vec
# for dof in boundary_dofs:
# Amat[dof] = 0
# Amat[dof, dof] = 1
# bvec[dof] = 0
# convert numpy matrix to dolfin.cpp.la.PETScMatrix
AMat = PETSc.Mat().createAIJ(Amat.shape)
AMat.setUp()
AMat.setValues(range(0, Amat.shape[0]), range(0, Amat.shape[1]), Amat)
AMat.assemble()
AMat = PETScMatrix(AMat)
# convert numpy vector to dolfin.cpp.la.PETScVector
bVec = PETSc.Vec().createSeq(V3.dim())
bVec.setValues(range(0,V3.dim()), bvec)
bVec = PETScVector(bVec)
w = Function(V3)
solve(AMat, w.vector(), -bVec)
# doing Backtrack line search
tol_l = 1e-4
c2 = 1e-4
c1 = 0.6
stepsize = alpha
starting = u0
direction = w
Jw_value = assemble(J(w,uD,eta))
Jz0_value = assemble(J(u0,uD,eta))
Dwg_u0_g = Discrete_weak_gradient(direction,uD)
Dwg_dire_0 = Discrete_weak_gradient(direction,Constant(0.0))
dJudz0 = dJudv_value(starting,uD,direction,eta,Dwg_u0_g,Dwg_dire_0)
zn = Function(V3)
iter_l = 0
while stepsize>tol_l:
print("****line search iter=%d: stepsize=%.16f ****"%(iter_l,stepsize))
iter_l = iter_l + 1
zn = starting+stepsize*direction
Jzn_value = assemble(J(zn,uD,eta))
if Jzn_value < Jz0_value+c2*stepsize*dJudz0:
break
else:
stepsize = c1*stepsize
print("After doing line search: ")
print("iter_stepsize=%d:" %iter_l)
print ("stepsize=%.16f Jz0=%.16f Jw=%.16f Jzn=%.16f Juex=%.16f" %(stepsize, Jz0_value, Jw_value, Jzn_value, Juex_value))
alpha = stepsize
u = u0 + alpha * w
u_er = project(w, V3)
u_exer = project(u-uex, V3)
u_L2iter = sqrt(assemble(inner(u_er,u_er)*dx))
uex_L2iter = sqrt(assemble(inner(u_exer,u_exer)*dx))
eps = u_L2iter
eps_ex = uex_L2iter
print ("iter=%d: error_iter=%.16f error_ex=%.16f" %(iter, eps, eps_ex))
print (" ")
u0 = u
iter = iter + 1
# error computation
plt.figure()
c = plot(u)
plt.colorbar(c)
plt.title('u DG solution')
plt.legend()
plt.show()
q = project(grad(u), V1)
sigma = pow(sqrt(inner(grad(u), grad(u))),p-2)*grad(u)
sigma = project(sigma, V2)
u = project(u, V3)
V1 = FunctionSpace(mesh, P1); V2 = FunctionSpace(mesh, P2); V3 = FunctionSpace(mesh, P3)
qer = project(q-qex, V1)
sigmaer = project(sigma-sigmaex, V2)
uer = project(u-uex, V3)
q_L2er = sqrt( assemble(inner(qer,qer)*dx) )
sigma_L2er = sqrt( assemble(inner(sigmaer,sigmaer)*dx) )
u_L2er = sqrt( assemble(uer*uer*dx) )
print ("\n")
print("p = %d " %p)
print("u : degree %d , q : degree %d, sigma : degree %d" %(pdeg,pdeg,pdeg))
print("mesh = %d x %d x 2" %(size,size))
print ("|u-uh|_{L2} \t |q-qh|_{L2} \t |sigma-sigmah|_{L2}")
print ("%.16f \t %.16f \t %.16f" % (u_L2er, q_L2er, sigma_L2er))
print ("\n")