Hello,
I am trying to solve the pde -laplacianU + q*U^2 =0 with with Dirichlet complex boundary values, when solving it for constant values for the function q the error is small but with a complex variable function q the error is big even with higher resolution or degree for Lagrange poly, like in this example :
#(FEniCS 2019.1)
from dolfin import *
import numpy as np
# -----------------------------------------
# Mixed real–imag Newton solve
# -----------------------------------------
def newton_solve_complex(mesh, V, q_fun, uD_fun, p=2, quad_deg=10):
# Mixed space W = V x V (real, imag)
W = FunctionSpace(mesh, MixedElement(\[V.ufl_element(), V.ufl_element()\]))
# Unknown, tests, trial for Jacobian
w = Function(W) # (u_R, u_I)
u_R, u_I = split(w)
v_R, v_I = TestFunctions(W)
dw = TrialFunction(W)
# q(x): split to real/imag via UserExpression -> interpolate to V
class QRe(UserExpression):
def eval(self, values, x): values\[0\] = float(np.real(q_fun(x)))
def value_shape(self): return ()
class QIm(UserExpression):
def eval(self, values, x): values\[0\] = float(np.imag(q_fun(x)))
def value_shape(self): return ()
q_R = interpolate(QRe(degree=4), V)
q_I = interpolate(QIm(degree=4), V)
# Dirichlet data u_D = uD_fun(x) split into real/imag
class UDR(UserExpression):
def eval(self, values, x): values\[0\] = float(np.real(uD_fun(x)))
def value_shape(self): return ()
class UDI(UserExpression):
def eval(self, values, x): values\[0\] = float(np.imag(uD_fun(x)))
def value_shape(self): return ()
uD_R = interpolate(UDR(degree=4), V)
uD_I = interpolate(UDI(degree=4), V)
bc_R = DirichletBC(W.sub(0), uD_R, "on_boundary")
bc_I = DirichletBC(W.sub(1), uD_I, "on_boundary")
bcs = \[bc_R, bc_I\]
# Nonlinearity: (u_R + i u_I)^2
u2_R = u_R\*u_R - u_I\*u_I
u2_I = 2.0\*u_R\*u_I
# q u^2
Re_qu2 = q_R\*u2_R - q_I\*u2_I
Im_qu2 = q_R\*u2_I + q_I\*u2_R
dxm = dx(metadata={"quadrature_degree": quad_deg})
# Residual (two real equations)
F_R = inner(grad(u_R), grad(v_R))\*dxm + Re_qu2\*v_R\*dxm
F_I = inner(grad(u_I), grad(v_I))\*dxm + Im_qu2\*v_I\*dxm
F = F_R + F_I
\# Jacobian
J = derivative(F, w, dw)
prm = {"newton_solver": {"absolute_tolerance": 1e-10,
"relative_tolerance": 1e-10,
"maximum_iterations": 50,
"linear_solver": "mumps"}}
solve(F == 0, w, bcs, J=J, solver_parameters=prm,
form_compiler_parameters={"quadrature_degree": quad_deg})
uR_fun, uI_fun = w.split(deepcopy=True)
return uR_fun, uI_fun
# -----------------------------------------
# Manufactured exact solution & q
# -----------------------------------------
k = 5.0
l = 5.0
def u_exact(x): # complex
return np.exp(1j\*(k\*x\[0\] + l\*x\[1\]))
def q_function(x): # complex
return -(k\*\*2 + l\*\*2) \* np.exp(-1j\*(k\*x\[0\] + l\*x\[1\]))
# -----------------------------------------
# Run small test
# -----------------------------------------
if __name__ == "__main__":
# Mesh and space
resolution = 64
mesh = RectangleMesh(Point(-1, -1), Point(1, 1), resolution, resolution)
V = FunctionSpace(mesh, "Lagrange", 2)
# Solve
u_R, u_I = newton_solve_complex(mesh, V, q_function, u_exact, p=2, quad_deg=12)
# Exact functions on V (for errors)
class UExactRe(UserExpression):
def eval(self, values, x): values\[0\] = float(np.real(u_exact(x)))
def value_shape(self): return ()
class UExactIm(UserExpression):
def eval(self, values, x): values\[0\] = float(np.imag(u_exact(x)))
def value_shape(self): return ()
uR_ex = interpolate(UExactRe(degree=5), V)
uI_ex = interpolate(UExactIm(degree=5), V)
dxm = dx(metadata={"quadrature_degree": 12})
dsm = ds(metadata={"quadrature_degree": 12})
# Domain L2 error
err_dom = np.sqrt(assemble(((u_R - uR_ex)\*\*2 + (u_I - uI_ex)\*\*2) \* dxm))
print("Domain L2 error (complex):", err_dom)
# Boundary normal derivative error
n = FacetNormal(mesh)
dn_num_re = dot(grad(u_R), n); dn_ex_re = dot(grad(uR_ex), n)
dn_num_im = dot(grad(u_I), n); dn_ex_im = dot(grad(uI_ex), n)
err_bnd = np.sqrt(assemble(((dn_num_re - dn_ex_re)\*\*2 + (dn_num_im - dn_ex_im)\*\*2) \* dsm))
print("Boundary L2 error of normal derivative (complex):", err_bnd)