Using fitted FEM to solve the interface problem, how to calculate the curve integral?

The region is splited into Omega1 and Omega2 by a interface Gamma. When the solution is discontinuous on Gamma, we need to consider the jump conditions in weak formulation, assume [\beta*u \dot n]=g, how I calculate <g,v>, where <> denotes L2 inner product on Gamma, v is a test function. My code is as follows, I think the part the confused me is wrong.

from fenics import *
from mshr import *
import numpy as np
import time

# Define variables
ax, ay, bx, by = -1.0, -1.0, 1.0, 1.0
Nx = Ny = 20
r0 = 1 / 2

# Define geometry for background and subdomains
domain = Rectangle(Point(ax, ay), Point(bx, by))
out = Rectangle(Point(ax, ay), Point(bx, by)) - Circle(Point(0, 0), r0)
circle = Circle(Point(0, 0), r0)

# Set subdomains
domain.set_subdomain(2, out)
domain.set_subdomain(1, circle)

start_time = time.time()

# Generate mesh
mesh = generate_mesh(domain, Nx)
meshfile = File("mesh.pvd")
meshfile << mesh

# Display max mesh size
hmax = mesh.hmax()
print('max h', hmax, 'for mesh N', Nx)

# Function space and subdomain markers
V = FunctionSpace(mesh, 'P', 1)
markers = MeshFunction('size_t', mesh, 2, mesh.domains())

# Define material properties
alfa = 2
beta1 = 1
beta2 = 1

class Beta(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = beta1
        else:
            values[0] = beta2

beta = Beta(markers, degree=0)

# Define w
class W(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = 10*(x[0]+x[1])-(5*np.exp(pow(x[0],2)+pow(x[1],2))+20)
        else:
            values[0] = 0

w = W(markers, degree=0)

# Define boundary condition
p_D = Expression('10*(x[0]+x[1])', degree=2)

def boundary(x):
    tol = 1e-15
    return abs(x[0] - ax) < tol or abs(x[0] - bx) < tol or abs(x[1] - ay) < tol or abs(x[1] - by) < tol

bc = DirichletBC(V, p_D, boundary)

# Define measures with subdomain data
dx = Measure('dx', domain=mesh, subdomain_data=markers)
ds = Measure("ds", domain=mesh, subdomain_data=None)

# Define source term
class F(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = (20*pow(x[0],2)+10)*np.exp(pow(x[0],2)+pow(x[1],2))
        else:
            values[0] = 0

f = F(markers, degree=0)

u2 = Expression("10*(x[0]+x[1])", degree=2)
u1 = Expression("5*np.exp(pow(x[0],2)+pow(x[1],2))+20", degree=2)

# Define variational problem
n = FacetNormal(mesh)
p = TrialFunction(V)
v = TestFunction(V)
a = beta * dot(grad(p), grad(v)) * dx
L = f * v * dx(1) + f * v * dx(2) + beta * dot(grad(w), grad(v)) * dx -  dot(u2-u1, n) * v *ds

# Compute solution
p = Function(V)
solve(a == L, p, bc)
u = p-w

# Save solution to file
vtkfile = File('u.pvd')
vtkfile << u

end_time = time.time()
elapsed_time = end_time - start_time
print('time:', elapsed_time)

# Define exact solution
class u_exact(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = 5*np.exp(pow(x[0],2)+pow(x[1],2))+20
        else:
            values[0] = 10*(x[0]+x[1])

u_e = u_exact(markers, degree=2)

# Interpolate exact solution for error calculation
u_e_ = interpolate(u_e, V)
file = File("u_e.pvd")
file << u_e_

# Compute error in L2 norm
error_L2 = errornorm(u_e, u, 'L2')
u_L2 = norm(u, 'L2')

# Compute maximum error at vertices
vertex_values_u_e = u_e_.compute_vertex_values(mesh)
vertex_values_u = u.compute_vertex_values(mesh)
error_max = np.max(np.abs(vertex_values_u_e - vertex_values_u))
r_L2 = error_L2/u_L2

num_dofs = V.dim()
print("自由度的个数:", num_dofs)

# Print errors
print('error_L2:', error_L2, 'for N =', Nx)
print('relative_error_L2:', r_L2, 'for N =', Nx)
print('error_max:', error_max, 'for N =', Nx)

ok, I think I have known how to calculate it, but Fenics tells me Cannot determine geometric dimension from expression. I can’t run my code. My code and bug are as follows. Any help is appreciated. Thanks!

from fenics import *
from mshr import *
import time
import numpy as np

# Define variables
ax, ay, bx, by = -1.0, -1.0, 1.0, 1.0
Nx = Ny = 20
r0 = 1 / 2

# Define geometry for background and subdomains
domain = Rectangle(Point(ax, ay), Point(bx, by))
out = Rectangle(Point(ax, ay), Point(bx, by)) - Circle(Point(0, 0), r0)
circle = Circle(Point(0, 0), r0)

# Set subdomains
domain.set_subdomain(2, out)
domain.set_subdomain(1, circle)

start_time = time.time()

# Generate mesh
mesh = generate_mesh(domain, Nx)
meshfile = File("mesh.pvd")
meshfile << mesh

# Display max mesh size
hmax = mesh.hmax()
print('max h', hmax, 'for mesh N', Nx)

# Function space and subdomain markers
V = FunctionSpace(mesh, 'P', 1)
markers = MeshFunction('size_t', mesh, 2, mesh.domains())

# Define material properties
alfa = 2
beta1 = 1
beta2 = 1

class Beta(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = beta1
        else:
            values[0] = beta2

beta = Beta(markers, degree=0)

# Define w
class W(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = 10 * (x[0] + x[1]) - (5 * exp(x[0]**2 + x[1]**2) + 20)
        else:
            values[0] = 0

w = W(markers, degree=0)

# Define boundary condition
p_D = Expression('10*(x[0]+x[1])', degree=2)

def boundary(x):
    tol = 1e-15
    return abs(x[0] - ax) < tol or abs(x[0] - bx) < tol or abs(x[1] - ay) < tol or abs(x[1] - by) < tol

bc = DirichletBC(V, p_D, boundary)

# Define measures with subdomain data
dx = Measure('dx', domain=mesh, subdomain_data=markers)
ds = Measure('ds', domain=mesh, subdomain_data=markers)

# Define source term
class F(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = -(20 * x[0]**2 + 10) * exp(x[0]**2 + x[1]**2)
        else:
            values[0] = 0

f = F(markers, degree=0)

# 使用正确的表达式
class u2(UserExpression):
    def eval(self, value, x):
        value[0] = 10*(x[0]+x[1])
    
class u1(UserExpression):
    def eval(self, value, x):
        value[0] = 5*exp(x[0]*x[0] + x[1]*x[1]) + 20

# u2 = Expression("10*(x[0]+x[1])", degree=2)
# u1 = Expression("5*exp(x[0]*x[0] + x[1]*x[1]) + 20", degree=2)

# Define variational problem
n = FacetNormal(mesh)
p = TrialFunction(V)
v = TestFunction(V)

# 确保右边的所有项都是标量 (L右端对内部区域的边界进行积分)
a = beta * inner(grad(p), grad(v)) * dx
L = f * v * dx(1) + f * v * dx(2) + beta * inner(grad(w), grad(v)) * dx - inner(u2 - u1, n) * v * ds(1)    

# Compute solution
p = Function(V)
solve(a == L, p, bc)
u = p - w

# Save solution to file
vtkfile = File('u.pvd')
vtkfile << u

end_time = time.time()
elapsed_time = end_time - start_time
print('time:', elapsed_time)

# Define exact solution
class u_exact(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers

    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = 5 * exp(x[0]**2 + x[1]**2) + 20
        else:
            values[0] = 10 * (x[0] + x[1])

u_e = u_exact(markers, degree=2)

# Interpolate exact solution for error calculation
u_e_ = interpolate(u_e, V)
file = File("u_e.pvd")
file << u_e_

# Compute error in L2 norm
error_L2 = errornorm(u_e, u, 'L2')
u_e_L2 = norm(u_e_, 'L2')

# Compute maximum error at vertices
vertex_values_u_e = u_e_.compute_vertex_values(mesh)
vertex_values_u = u.compute_vertex_values(mesh)
error_max = np.max(np.abs(vertex_values_u_e - vertex_values_u))
r_L2 = error_L2 / u_e_L2

num_dofs = V.dim()
print("自由度的个数:", num_dofs)

# Print errors
print('error_L2:', error_L2, 'for N =', Nx)
print('relative_error_L2:', r_L2, 'for N =', Nx)
print('error_max:', error_max, 'for N =', Nx)

bug:

WARNING: user expression has not supplied value_shape method or an element. Assuming scalar element.
WARNING: user expression has not supplied value_shape method or an element. Assuming scalar element.
WARNING: user expression has not supplied value_shape method or an element. Assuming scalar element.
Cannot determine geometric dimension from expression.
Traceback (most recent call last):
  File "/home/yunlong/fem_code/interface_problem/interface2d-d.py", line 110, in <module>
    L = f * v * dx(1) + f * v * dx(2) + beta * inner(grad(w), grad(v)) * dx - inner(u2 - u1, n) * v * ds(1)    
  File "/usr/lib/python3/dist-packages/ufl_legacy/operators.py", line 370, in grad
    return Grad(f)
  File "/usr/lib/python3/dist-packages/ufl_legacy/differentiation.py", line 140, in __new__
    dim = find_geometric_dimension(f)
  File "/usr/lib/python3/dist-packages/ufl_legacy/domain.py", line 376, in find_geometric_dimension
    error("Cannot determine geometric dimension from expression.")
  File "/usr/lib/python3/dist-packages/ufl_legacy/log.py", line 158, in error
    raise self._exception_type(self._format_raw(*message))
ufl_legacy.log.UFLException: Cannot determine geometric dimension from expression.

Supply a keyword argument for the domain to your user-expression at construction.
https://bitbucket.org/fenics-project/dolfin/src/1c52e837eb54cc34627f90bde254be4aa8a2ae17/python/dolfin/function/expression.py?at=master#lines-251

Thanks for your advice.

Forgive me for the rough description earlier, I I give a full description of the problem and the latest version of the code, the L2 error is wrong. Any help is appreciated. Thanks!

from fenics import *
from mshr import *
import time
import numpy as np

# Define variables
ax, ay, bx, by = -1.0, -1.0, 1.0, 1.0
Nx = Ny = 20
r0 = 1 / 2

# Define geometry for background and subdomains
domain = Rectangle(Point(ax, ay), Point(bx, by))
out = Rectangle(Point(ax, ay), Point(bx, by)) - Circle(Point(0, 0), r0)
circle = Circle(Point(0, 0), r0)

# Set subdomains
domain.set_subdomain(2, out)
domain.set_subdomain(1, circle)

start_time = time.time()

# Generate mesh
mesh = generate_mesh(domain, Nx)
meshfile = File("mesh.pvd")
meshfile << mesh

# Display max mesh size
hmax = mesh.hmax()
print('max h', hmax, 'for mesh N', Nx)

# Function space and subdomain markers
V = FunctionSpace(mesh, 'P', 1)
markers = MeshFunction('size_t', mesh, 2, mesh.domains())

# Define material properties
alfa = 2
beta1 = 1
beta2 = 1

class Beta(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
        self.domain = domain
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = beta1
        else:
            values[0] = beta2

beta = Beta(markers, degree=0)

# Define w
class W(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
        self.domain = domain
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = 10 * (x[0] + x[1]) - (5 * exp(x[0]**2 + x[1]**2) + 20)
        else:
            values[0] = 0

w = W(markers, degree=0)

# Define boundary condition
p_D = Expression('10*(x[0]+x[1])', degree=2)

def boundary(x):
    tol = 1e-15
    return abs(x[0] - ax) < tol or abs(x[0] - bx) < tol or abs(x[1] - ay) < tol or abs(x[1] - by) < tol

bc = DirichletBC(V, p_D, boundary)

# # Define measures with subdomain data
# dx = Measure('dx', domain=mesh, subdomain_data=markers)
# ds = Measure('ds', domain=mesh, subdomain_data=markers)

# Define source term
class F(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
        self.domain = domain
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = -20 * (x[0]**2 + x[1]**2 + 10) * exp(x[0]**2 + x[1]**2)
        else:
            values[0] = 0

f = F(markers, degree=0)


# Define variational problem
n = FacetNormal(mesh)
p = TrialFunction(V)
v = TestFunction(V)
w_e = interpolate(w, V)


# weak formulation
a = beta * inner(grad(p), grad(v)) * dx 
L = f * v * dx(1) + f * v * dx(2) + beta * inner(grad(w_e), grad(v)) * dx - inner(grad(w_e), n) * v * ds(1)   


# Compute solution
p = Function(V)
solve(a == L, p, bc)


end_time = time.time()
elapsed_time = end_time - start_time
print('time:', elapsed_time)

# Define exact solution
class u_exact(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
        self.domain = domain
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = 5 * exp(x[0]**2 + x[1]**2) + 20
        else:
            values[0] = 10 * (x[0] + x[1])

u_e = u_exact(markers, degree=2)

# Define exact solution
class p_exact(UserExpression):
    def __init__(self, markers, **kwargs):
        super().__init__(**kwargs)
        self.markers = markers
        self.domain = domain
    def eval_cell(self, values, x, cell):
        if self.markers[cell.index] == 1:
            values[0] = 10 * (x[0] + x[1])
        else:
            values[0] = 10 * (x[0] + x[1])

p_e = p_exact(markers, degree=2)

# Interpolate exact solution for error calculation
u_e_ = interpolate(u_e, V)
file = File("u_e.pvd")
file << u_e_

# Interpolate exact solution for error calculation
p_e_ = interpolate(p_e, V)
file = File("p_e.pvd")
file << p_e_

# Compute error in L2 norm
error_L2 = errornorm(p_e, p, 'L2')      #u=p-w,u-u_e = p - (u_e+w)=p-p_e
u_e_L2 = norm(u_e_, 'L2')

# Compute maximum error at vertices
vertex_values_p_e = p_e_.compute_vertex_values(mesh)
vertex_values_p = p.compute_vertex_values(mesh)
error_max = np.max(np.abs(vertex_values_p_e - vertex_values_p))
r_L2 = error_L2 / u_e_L2

num_dofs = V.dim()
print("number of DoF:", num_dofs)

# Print errors
print('error_L2:', error_L2, 'for N =', Nx)
print('relative_error_L2:', r_L2, 'for N =', Nx)
print('error_max:', error_max, 'for N =', Nx)

I don’t understand where you are trying to enforce the jump discontinuity of u in your code.

I would strongly suggest looking at

as your formulation will surely be of a similar flavor, either with a pure DG method, or with the mixed approach I presented in DOLFINx

Thanks for your advice, I have solved my question by reading the Fenics documentation, section1.5.3 is all I want to know.
About the jump condition, as you see, exact solution u is discontinuous, and I set
p = u + w, where w =u2-u1 at the interface (w is discontinuous on \Omega, and it could be any function that satisfs w=u2-u1 on \Gamma, we choose it), then p is continuous, I solve p firstly, then achieve u by u = p - w, so I can use conforming FEM to solve the discontinuous interface problem.

I would strongly suggest you post the code resolving the issues you have on the forum, to help others at a later stage.
If the thread is not resolved, I would:

  1. Start by checking with a solution that is continuous at the interface (would be like setting w= on \Gamma, to check that all other boundary conditions, and the PDE is well formulated). If it works for the continuous case, that would indicate that the back-substitution is the issue.
  2. Show prints of the current errors for various mesh sizes.

OK, Sir, I am still struggle for the code now, I will post my code when I solve my problems.

I have solved this problem by Python. The mesh is generated by Gmsh, then I compute numerical integration in the weak form.