Maxwell SL with preconditioner#
from ngsolve import *
from netgen.occ import *
from ngsolve.webgui import Draw
from ngsolve.bem import *
face = Glue(Sphere((0,0,0),1).faces)
mesh = Mesh(OCCGeometry(face).GenerateMesh(maxh=0.1)).Curve(4)
Draw (mesh);
visplane = WorkPlane(Axes((0,0,0), Z, X)).RectangleC(5,5).Face()
vismesh = Mesh(OCCGeometry(visplane).GenerateMesh(maxh=0.2))
Draw (vismesh);
kappa = 3*pi
d = CF((0,-kappa,0))
E_inc = exp(1j*d*CF((x,y,z))) * CF((1,0,0))
Draw (E_inc[0], vismesh, animate_complex=True, order=3);
fes = HDivSurface(mesh, order=3, complex=True)
u,v = fes.TnT()
fespot = H1(mesh, order=4, complex=True)
upot, vpot = fespot.TnT()
with TaskManager():
V1 = HelmholtzSL(u.Trace()*ds(bonus_intorder=4), kappa)*v.Trace()*ds(bonus_intorder=4)
V2 = HelmholtzSL(div(u.Trace())*ds(bonus_intorder=4), kappa)*div(v.Trace())*ds(bonus_intorder=4)
lhs = (1j*kappa) * V1.mat + 1/(1j*kappa) * V2.mat
rhs = LinearForm(E_inc*v.Trace()*ds(bonus_intorder=3)).Assemble()
preconditioner is $\( (\cdot \times n) @ V @ (\cdot \times n) \)$
invMHd = BilinearForm(u.Trace()*v.Trace()*ds).Assemble().mat.Inverse(inverse="sparsecholesky")
n = specialcf.normal(3)
with TaskManager():
Vrot = HelmholtzSL(Cross(u.Trace(),n)*ds(bonus_intorder=2), kappa)*Cross(v.Trace(),n)*ds(bonus_intorder=2)
Vpot = HelmholtzSL(upot*ds(bonus_intorder=2), kappa)*vpot*ds(bonus_intorder=2)
surfcurl = BilinearForm(Cross(grad(upot).Trace(), n)*v.Trace()*ds).Assemble().mat
invMH1 = BilinearForm(upot*vpot*ds).Assemble().mat.Inverse(inverse="sparsecholesky")
pre = invMHd @ ( kappa*Vrot.mat - 1/kappa*surfcurl@invMH1@Vpot.mat@invMH1@surfcurl.T) @ invMHd
gfj = GridFunction(fes)
from time import time
ts = time()
with TaskManager():
gfj.vec[:] = solvers.GMRes(A=lhs, b=rhs.vec, pre=pre, maxsteps=500, tol=1e-8)
te = time()
print ("time=", te-ts)
GMRES iteration 1, residual = 2.0872552460981177
GMRES iteration 2, residual = 0.8433834622783686
GMRES iteration 3, residual = 0.4577402159706648
GMRES iteration 4, residual = 0.30210716607024823
GMRES iteration 5, residual = 0.2192123586448595
GMRES iteration 6, residual = 0.18262653379843952
GMRES iteration 7, residual = 0.13313336375759927
GMRES iteration 8, residual = 0.05080497746867199
GMRES iteration 9, residual = 0.03392193652672886
GMRES iteration 10, residual = 0.013092407942040654
GMRES iteration 11, residual = 0.009112513240253705
GMRES iteration 12, residual = 0.0007753709392715611
GMRES iteration 13, residual = 0.00010301894044587265
GMRES iteration 14, residual = 1.9220876415732964e-05
GMRES iteration 15, residual = 4.005172772596476e-06
GMRES iteration 16, residual = 1.7426778712070648e-06
GMRES iteration 17, residual = 4.0853479856449564e-07
GMRES iteration 18, residual = 1.8137917151343438e-07
GMRES iteration 19, residual = 8.370880836771866e-08
GMRES iteration 20, residual = 4.7861878871679306e-08
GMRES iteration 21, residual = 2.845053334601645e-08
GMRES iteration 22, residual = 1.553356429777655e-08
GMRES iteration 23, residual = 6.4359503487042576e-09
time= 298.69758677482605
Draw( gfj[0], mesh, draw_vol=False, order=3, min=-2, max=2, animate_complex=True);
fes_screen = VectorH1(vismesh, order=3, complex=True)
E_screen = GridFunction(fes_screen)
E_screen.Set(1j*kappa*HelmholtzSL(u.Trace()*ds(bonus_intorder=4), kappa)(gfj) \
-1/(1j*kappa)*grad(HelmholtzSL(div(u.Trace())*ds(bonus_intorder=4), kappa)(gfj)) \
, definedon=vismesh.Boundaries(".*"))
Draw ( (E_inc-E_screen)[0], vismesh, animate_complex=True, min=-1, max=1)
Draw ( (E_inc)[0].real, vismesh, animate_complex=True, min=-1, max=1)
Draw ( (E_screen)[0].real, vismesh, animate_complex=True, min=-1, max=1)
WebGLScene