I have created a simplified version of my code.
from fenics import *
import numpy as np
T = 2.0 # final time
num_steps = 10 # number of time steps
dt = T / num_steps # time step size
alpha = 3 # parameter alpha
beta = 1.2 # parameter beta
# Create mesh and define function space
nx = ny = 8
mesh = UnitSquareMesh(nx, ny)
V = FunctionSpace(mesh, 'P', 1)
# Define boundary condition
u_D = Expression('1 + x[0]*x[0] + alpha*x[1]*x[1] + beta*t',
degree=2, alpha=alpha, beta=beta, t=0)
def right(x, on_boundary):
return near(x[0], 1)
def btm(x, on_boundary):
return near(x[1], 0)
def top(x, on_boundary):
return near(x[1], 1)
bc_right = DirichletBC(V, u_D, right)
bc_btm = DirichletBC(V, u_D, btm)
bc_top = DirichletBC(V, u_D, top)
bcs = [bc_right, bc_btm, bc_top]
left_bc_markers = MeshFunction('size_t', mesh, mesh.topology().dim() - 1)
sub_domains = np.linspace(0, 1, 11)
for i in range(len(sub_domains)-1):
class left_bc(SubDomain):
def inside(self, x, on_boundary):
return x[1] <= sub_domains[i+1] and x[1] >= sub_domains[i] and near(x[0], 0)
bx0 = left_bc()
bx0.mark(left_bc_markers,i+1)
# Define initial value
u_n = interpolate(u_D, V)
#u_n = project(u_D, V)
# Define variational problem
u = TrialFunction(V)
v = TestFunction(V)
f = Constant(beta - 2 - 2*alpha)
F = u*v*dx + dt*dot(grad(u), grad(v))*dx - (u_n + dt*f)*v*dx
a, L = lhs(F), rhs(F)
# Time-stepping
u = Function(V)
t = 0
for n in range(num_steps):
# Update current time
t += dt
u_D.t = t
ds_sub = Measure("ds", domain = mesh, subdomain_data=left_bc_markers)
qn = np.random.default_rng().uniform(1,10,len(sub_domains)-1)
print(qn)
L_BC = 0
for i in range(len(sub_domains)-1):
L_BC += dt*v*qn[i]*ds_sub(i+1)
L_Final = L + L_BC
# Compute solution
solve(a == L_Final, u, bcs)
# Update previous solution
u_n.assign(u)
The key idea is the Neumann boundary depends on the location discretely, so I divided the boundary into N subdomains with each subdomains having a value of qn.