This page was generated from unit-11.3-bem-Helmholtz/BrakhageWerner.ipynb.

11.3.1 Helmholtz solver using Brakhage-Werner formulation

Combined field integral equations combine single and double layer integral operators, one simple option is the Brakhage-Werner formulation.

The solution is represented as

\[u = (i \kappa S - D) \phi,\]

where \(\phi\) solve the boundary integral equation

\[\big( \tfrac{1}{2} + K + i \kappa V \big) \phi = u_{in} \qquad \text{on} \, \Gamma\]
[1]:
from netgen.occ import *
from ngsolve import *
from ngsolve.webgui import Draw
from ngsolve.bem import *
[2]:
kappa=10
order=4
[3]:
screen = WorkPlane(Axes( (0,0,0), Z, X)).RectangleC(15,15).Face()
sphere = Sphere( (0,0,0), pi)
screen = screen - sphere
sp = Fuse(sphere.faces)
screen.faces.name="screen"
sp.faces.name="sphere"
shape = Compound([screen,sp])

mesh = shape.GenerateMesh(maxh=5/kappa).Curve(order)
Draw (mesh);
[4]:
fes_sphere = Compress(SurfaceL2(mesh, order=order, complex=True, definedon=mesh.Boundaries("sphere")))
u,v = fes_sphere.TnT()
fes_screen = Compress(SurfaceL2(mesh, order=order, dual_mapping=True, complex=True, definedon=mesh.Boundaries("screen")))
print ("ndof_sphere = ", fes_sphere.ndof, "ndof_screen =", fes_screen.ndof)
ndof_sphere =  17010 ndof_screen = 24375
[ ]:

[5]:
with TaskManager():
    C = HelmholtzCF(u*ds("sphere"), kappa)*v*ds
    Id = BilinearForm(u*v*ds).Assemble()
[6]:
with TaskManager():
    lhs = 0.5 * Id.mat + C.mat
    source = exp(1j * kappa * x)
    rhs = LinearForm(-source*v*ds).Assemble()
[7]:
gfu = GridFunction(fes_sphere)
pre = BilinearForm(u*v*ds, diagonal=True).Assemble().mat.Inverse()
with TaskManager():
    gfu.vec[:] = solvers.GMRes(A=lhs, b=rhs.vec, pre=pre, maxsteps=40, tol=1e-8)
GMRES iteration 1, residual = 60.52577349082924
GMRES iteration 2, residual = 24.009676873189584
GMRES iteration 3, residual = 10.824804473872812
GMRES iteration 4, residual = 5.186787179809056
GMRES iteration 5, residual = 2.5576056367857167
GMRES iteration 6, residual = 1.2971173258195763
GMRES iteration 7, residual = 0.663570953505612
GMRES iteration 8, residual = 0.363876841512764
GMRES iteration 9, residual = 0.2068470336616884
GMRES iteration 10, residual = 0.11438646943080959
GMRES iteration 11, residual = 0.06227575935405564
GMRES iteration 12, residual = 0.034637935111723486
GMRES iteration 13, residual = 0.014305457232883009
GMRES iteration 14, residual = 0.007615830819100469
GMRES iteration 15, residual = 0.0034590712214675034
GMRES iteration 16, residual = 0.0020405238070011758
GMRES iteration 17, residual = 0.0012014327295967924
GMRES iteration 18, residual = 0.0007148135278931926
GMRES iteration 19, residual = 0.0004224517404581818
GMRES iteration 20, residual = 0.00024346964229461402
GMRES iteration 21, residual = 0.00013063554226842324
GMRES iteration 22, residual = 7.60853112762455e-05
GMRES iteration 23, residual = 4.488558707573031e-05
GMRES iteration 24, residual = 2.3325943111224232e-05
GMRES iteration 25, residual = 1.179765231910189e-05
GMRES iteration 26, residual = 5.883136875403311e-06
GMRES iteration 27, residual = 2.9032125984977697e-06
GMRES iteration 28, residual = 1.4456598616366854e-06
GMRES iteration 29, residual = 8.139679993572748e-07
GMRES iteration 30, residual = 4.628238830299994e-07
GMRES iteration 31, residual = 2.7815709851066844e-07
GMRES iteration 32, residual = 1.6444207813564547e-07
GMRES iteration 33, residual = 9.716359581702717e-08
GMRES iteration 34, residual = 5.3318686547693835e-08
GMRES iteration 35, residual = 3.0495921233342266e-08
GMRES iteration 36, residual = 1.7935821055200712e-08
GMRES iteration 37, residual = 9.464519507417358e-09
[8]:
Draw (gfu, order=5, min=-1, max=1);

prostprocessing on screen

[9]:
uscat = GridFunction(fes_screen)
with TaskManager(pajetrace=10**8):
    intop = 1j*kappa*HelmholtzSL(u*ds("sphere"),kappa) + (-1)*HelmholtzDL(u*ds("sphere"), kappa)
    uscat.Set(intop(gfu, mesh.Boundaries("screen")), definedon=mesh.Boundaries("screen"))
[10]:
print ("Scattered field")
Draw (uscat, mesh, min=-1,max=1, animate_complex=True, order=4);
Scattered field
[11]:
uin = mesh.BoundaryCF( {"screen": source }, default=0)
print ("Total field")
Draw (uin-uscat, mesh, min=-1,max=1, animate_complex=True, order=4);
Total field

Scattering from sphere with \(D = 50 \lambda\). About 5 min on Macbook Apple M4 Pro

Alternative text

[ ]: