How to find the degrees of freedom on the boundary

Hi everyone,

I want to find the degrees of freedom on the boundary, and I have tried the following method.

from dolfin import * 
# dolfin.__version__ : 2019.2.0.dev0
import numpy as np

mesh = RectangleMesh(Point(0, 0), Point(1, 1), 2, 2)
P = FiniteElement("DG", triangle, 1)
V = FunctionSpace(mesh, P)
bc = DirichletBC(V, Constant(0.0) , "on_boundary")
u = Function(V)
u.vector()[:] = 1.0
bc.apply(u.vector())
boundary_dofs = np.where(u.vector()[:] == 0.0)
print(boundary_dofs)

But this method doesn’t seem correct

output:
boundary_dofs =  (array([], dtype=int64),)

How should I modify my code, or is there another method I can use?

Thanks!

A DG space has all DOFs in the interior, and Dirichlet BC are typically imposed weakly.

I see, thank you!

Sorry, may I ask another question? So, if I want to solve the linear system Ax=b, for example A=assemble(inner(grad(u),grad(v))*dx), b=assemble(f*v*dxāˆ’g*v*ds), is it unnecessary to apply bc.apply(A) and bc.apply(b)?

Because I want to add them respectively to a PETSc matrix/vector that I converted from NumPy, I need to solve the DG system using a linear system.

If you do not add any boundary conditions, you will have a singular system.

If you want to solve Poisson with pure Neumann, this is possible, see for instance
https://fenicsproject.org/olddocs/dolfin/latest/python/demos/singular-poisson/demo_singular-poisson.py.html
and
https://fenicsproject.org/olddocs/dolfin/latest/python/demos/neumann-poisson/demo_neumann-poisson.py.html

But please do note that you do not have a proper variational formulation for a DG system, as you are missing all the coupling terms between the cells.

1 Like

Thank you for your reply.

Sorry, I gave a not-so-good example. My question is, in the case of only Dirichlet boundary uD​, for example

A=assemble(inner(grad(u),grad(v))*dx+uD*u*v*ds), b=assemble(f*v*dx+inner(uD*n,v*n)*ds)

This is my simplified question.

If it’s just the above example, I can directly use bc.apply() and successfully solve Ax = b with solve(A, sol.vector(), b). However, since I want to add them respectively to a PETSc matrix/vector that I converted from NumPy, using bc.apply() causes an error (perhaps there is a structural issue with the NumPy array I constructed). That’s why I’m asking whether bc.apply() is needed in this situation.

I don’t know why you want the term:

in your problem.

Secondly, you need to apply Dirichlet bcs if you want to solve the correct problem.

Without a reproducible example of this behavior we can unfortunately not help you with this. There shouldn’t be anything particular about applying bcs.

The process of applying DirichletBCs in a symmetric/unsymmetric fashion is explained in
http://jsdokken.com/FEniCS23-tutorial/src/lifting.html

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")

This example is too lengthy for me to have time to look at its entirety.

Have you first tried to solve a simpler problem, like the equivalent Poisson equation, and made sure that you understand how to apply boundary conditions to that problem?

Yes, I have tried solving the Poisson equation using CG, and it seems that this method has no issues.

from dolfin import *
import numpy as np
from petsc4py import PETSc
from scipy.sparse import csr_matrix

mesh = UnitSquareMesh(8, 8)
V = FunctionSpace(mesh, "CG", 1)
u = TrialFunction(V)
v = TestFunction(V)

f = Expression("2*pow(pi, 2)*sin(pi*x[0])*sin(pi*x[1])", degree=5, pi=np.pi)
uex = Expression("sin(pi*x[0])*sin(pi*x[1])", degree=5, pi=np.pi)
uD = project(uex, V)
bc = DirichletBC(V, uD, "on_boundary")

L = f * v * dx
b = assemble(L)
b = as_backend_type(b)
bc.apply(b)

Amat = np.zeros((V.dim(), V.dim()))
dofmap = V.dofmap() 
global_dofs = dofmap.dofs()


# The term inner(grad(u), grad(v))
for i in range(V.dim()):
    phi_i = Function(V)
    phi_i.vector()[i] = 1
    for j in range(V.dim()):
        phi_j = Function(V)
        phi_j.vector()[j] = 1
        phijvec = assemble(inner(grad(phi_i), grad(phi_j)) * dx)
        Amat[global_dofs[i], global_dofs[j]] = phijvec


boundary_dofs = list(bc.get_boundary_values().keys())
print(boundary_dofs)
for dof in boundary_dofs:
  Amat[dof] = 0
  Amat[dof, dof] = 1


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)


sol = Function(V)
solve(AMat, sol.vector(), b)

uer = project(uex-sol,V)
u_L2er = sqrt( assemble(uer*uer*dx) )

print("u_L2 error:",u_L2er)
plot(sol)

But I encountered a problem applying the boundary conditions when using DG.

from fenics import *
from dolfin import *
from petsc4py import PETSc
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt


mesh = UnitSquareMesh(2, 2)
V = FunctionSpace(mesh, "DG", 1)
u = TrialFunction(V)
v = TestFunction(V)
alpha = Constant(10.0)
n = FacetNormal(mesh)
h = CellDiameter(mesh)
h_avg = (h('+') + h('-'))/2

f = Expression("2*pow(pi, 2)*sin(pi*x[0])*sin(pi*x[1])", degree=5, pi=np.pi)
uex = Expression("sin(pi*x[0])*sin(pi*x[1])", degree=5, pi=np.pi)
uD = project(uex, V)
bc = DirichletBC(V, uD ,"on_boundary")


Amat = np.zeros((V.dim(), V.dim()))
bvec = np.zeros(V.dim())
dofmap = V.dofmap() 
global_dofs = dofmap.dofs()


# The first term of a and L    
# dot( grad (u), grad (v) )*dx , f*v*dx
for i in range(V.dim()):
    phi_i = Function(V)
    phi_i.vector()[i] = 1
    phivalue = assemble(f * phi_i * dx)
    bvec[global_dofs[i]] = phivalue
    for j in range(V.dim()):
        phi_j = Function(V)
        phi_j.vector()[j] = 1
        phi_ij = assemble(inner(grad(phi_i), grad(phi_j)) * dx)
        Amat[global_dofs[i], global_dofs[j]] = phi_ij

a = assemble(-dot(avg(grad(u)),jump(v,n))*dS-dot(avg(grad(v)),jump(u,n))*dS\
    +alpha / h_avg *dot( jump (v, n), jump (u, n))*dS\
    -dot(grad(u),v*n)*ds-dot(grad(v),u*n)*ds\
    +alpha /h*u*v*ds )

L = assemble(-dot(grad(v),uD*n)*ds\
    +alpha /h*uD*v*ds )


Apetsc = as_backend_type(a).mat()
Apetsc = Apetsc.getValues(range(0, Apetsc.getSize()[0]), range(0,  Apetsc.getSize()[1]))
Amat = Amat - Apetsc


L_vec = L.get_local()
bvec = bvec - L_vec

# boundary_dofs = list(bc.get_boundary_values().keys())
# for dof in boundary_dofs:
#   Amat[dof] = 0
#   Amat[dof, dof] = 1

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 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(V.dim())
bVec.setValues(range(0,V.dim()), bvec)
bVec = PETScVector(bVec) 

sol = Function(V)
solve(AMat, sol.vector(), bVec)

uer = project(uex-sol,V)
u_L2er = sqrt( assemble(uer*uer*dx) )

print("u_L2 error:",u_L2er)
plot(sol)

That’s also why I wanted to ask how to find the degrees of freedom on the boundary when using DG.

Haven’t we been through this already?
Strong Dirichlet conditions does not make sense for DG.
You can see this with:

from dolfin import *
mesh = UnitSquareMesh(5, 5)
V = FunctionSpace(mesh, "CG", 1)

uh = Function(V)

u_ex = Expression("x[0]*x[0] + x[1]*x[1]", degree=2)
bc = DirichletBC(V, u_ex ,"on_boundary")
bc.apply(uh.vector())
with XDMFFile("uh.xdmf") as file:
    file.write_checkpoint(uh, "uh", 0.0, append=False)

which generates
image

while

from dolfin import *
mesh = UnitSquareMesh(5, 5)
V = FunctionSpace(mesh, "DG", 1)

uh = Function(V)

u_ex = Expression("x[0]*x[0] + x[1]*x[1]", degree=2)
bc = DirichletBC(V, u_ex ,"on_boundary")
bc.apply(uh.vector())
with XDMFFile("uh.xdmf") as file:
    file.write_checkpoint(uh, "uh", 0.0, append=False)

generates
image
as ā€œon_boundaryā€ only works for dofs associated with facets/vertices/edges, which no DG dof is.
You could do:

from dolfin import *
mesh = UnitSquareMesh(5, 5)
V = FunctionSpace(mesh, "DG", 1)

uh = Function(V)

u_ex = Expression("x[0]*x[0] + x[1]*x[1]", degree=2)
bc = DirichletBC(V, u_ex ,"near(x[0], 0)| near(x[0], 1) | near(x[1], 0) | near(x[1],1)", method="pointwise")
bc.apply(uh.vector())
with XDMFFile("uh.xdmf") as file:
    file.write_checkpoint(uh, "uh", 0.0, append=False)

resulting in a correct strong enforcement.
However, note as already mentioned, that one usually treats DG boundary conditions weakly with a Nitsche type formulation.

1 Like

Thank you for your reply!

Regarding using DG to solve the Poisson problem, I understand that when I treat the problem as a variational problem, the Dirichlet BCs are typically imposed weakly.

However, when I solve it as a linear system, do I need to handle the assembled matrix/vector differently?

If not, I think the issue might lie in how numpy assembles the components.

You would need to add the extra terms to your variational form.

As shown above, you don’t get Dirichlet enforcement strongly with your current code, leading to it being interpreted as a pure Neumann condition

1 Like

This is the result I got when I directly assembled the bilinear form
š‘Ž and the linear form š‘ from the variational problem and solved the linear system, which gave me the desired result.

from fenics import *
from dolfin import *
from petsc4py import PETSc
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt


mesh = UnitSquareMesh(2, 2)
V = FunctionSpace(mesh, "DG", 1)
u = TrialFunction(V)
v = TestFunction(V)
alpha = Constant(10.0)
n = FacetNormal(mesh)
h = CellDiameter(mesh)
h_avg = (h('+') + h('-'))/2

f = Expression("2*pow(pi, 2)*sin(pi*x[0])*sin(pi*x[1])", degree=5, pi=np.pi)
uex = Expression("sin(pi*x[0])*sin(pi*x[1])", degree=5, pi=np.pi)
uD = project(uex, V)
# bc = DirichletBC(V, uD ,"on_boundary")
# bc = DirichletBC(V, uD ,"near(x[0], 0)| near(x[0], 1) | near(x[1], 0) | near(x[1],1)", method="pointwise")


a = assemble(dot( grad (u), grad (v))*dx\
    -dot(avg(grad(u)),jump(v,n))*dS-dot(avg(grad(v)),jump(u,n))*dS\
    +alpha / h_avg *dot( jump (v, n), jump (u, n))*dS\
    -dot(grad(u),v*n)*ds-dot(grad(v),u*n)*ds\
    +alpha /h*u*v*ds)

L = assemble(f*v*dx\
    -dot(grad(v),uD*n)*ds\
    +alpha /h*uD*v*ds)


sol = Function(V)
solve(a, sol.vector() ,L)

uer = project(uex-sol,V)
u_L2er = sqrt( assemble(uer*uer*dx) )

print("u_L2 error:",u_L2er)

plt.figure()
c = plot(sol)
plt.colorbar(c)
plt.title('u DG solution')
plt.legend()
plt.show()

However, the following is the result when I used the code I provided above, but it produced an issue. I also tried modifying it based on your suggestion, but I still don’t know where the problem is.

from fenics import *
from dolfin import *
from petsc4py import PETSc
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt


mesh = UnitSquareMesh(2, 2)
V = FunctionSpace(mesh, "DG", 1)
u = TrialFunction(V)
v = TestFunction(V)
alpha = Constant(10.0)
n = FacetNormal(mesh)
h = CellDiameter(mesh)
h_avg = (h('+') + h('-'))/2

f = Expression("2*pow(pi, 2)*sin(pi*x[0])*sin(pi*x[1])", degree=5, pi=np.pi)
uex = Expression("sin(pi*x[0])*sin(pi*x[1])", degree=5, pi=np.pi)
uD = project(uex, V)
# bc = DirichletBC(V, uD ,"on_boundary")
# bc = DirichletBC(V, uD ,"near(x[0], 0)| near(x[0], 1) | near(x[1], 0) | near(x[1],1)", method="pointwise")

Amat = np.zeros((V.dim(), V.dim()))
bvec = np.zeros(V.dim())
dofmap = V.dofmap() 
global_dofs = dofmap.dofs()

# The first term of a and L    
# dot( grad (u), grad (v) )*dx , f*v*dx
for i in range(V.dim()):
    phi_i = Function(V)
    phi_i.vector()[i] = 1
    phivalue = assemble(f * phi_i * dx)
    bvec[global_dofs[i]] = phivalue
    for j in range(V.dim()):
        phi_j = Function(V)
        phi_j.vector()[j] = 1
        phi_ij = assemble(inner(grad(phi_i), grad(phi_j)) * dx)
        Amat[global_dofs[i], global_dofs[j]] = phi_ij

a = assemble(-dot(avg(grad(u)),jump(v,n))*dS-dot(avg(grad(v)),jump(u,n))*dS\
    +alpha / h_avg *dot( jump (v, n), jump (u, n))*dS\
    -dot(grad(u),v*n)*ds-dot(grad(v),u*n)*ds\
    +alpha /h*u*v*ds )

L = assemble(-dot(grad(v),uD*n)*ds\
    +alpha /h*uD*v*ds )


Apetsc = as_backend_type(a).mat()
Apetsc = Apetsc.getValues(range(0, Apetsc.getSize()[0]), range(0,  Apetsc.getSize()[1]))
Amat = Amat - Apetsc

L_vec = L.get_local()
bvec = bvec - L_vec

# boundary_dofs = list(bc.get_boundary_values().keys())
# for dof in boundary_dofs:
#   Amat[dof] = 0
#   Amat[dof, dof] = 1.0
#   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(V.dim())
bVec.setValues(range(0,V.dim()), bvec)
bVec = PETScVector(bVec) 

sol = Function(V)
solve(AMat, sol.vector(), bVec)

uer = project(uex-sol,V)
u_L2er = sqrt( assemble(uer*uer*dx) )

print("u_L2 error:",u_L2er)

plt.figure()
c = plot(sol)
plt.colorbar(c)
plt.title('u DG solution')
plt.legend()
plt.show()

Sorry, I found that the issue was that I got the signs wrong.
Amat = Amat + Apetsc
bvec = bvec + L_vec

Thank you for your help!