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()
sp = Fuse(Sphere( (0,0,0), pi).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 = 31110
[ ]:
[5]:
with TaskManager():
# V = HelmholtzSingleLayerPotentialOperator(fes_sphere, fes_sphere, kappa=kappa, intorder=10)
# K = HelmholtzDoubleLayerPotentialOperator(fes_sphere, fes_sphere, kappa=kappa, intorder=10)
# C = HelmholtzCombinedFieldOperator(fes_sphere, fes_sphere, kappa=kappa, intorder=10)
C = HelmholtzCF(u*ds("sphere"), kappa)*v*ds
u,v = fes_sphere.TnT()
Id = BilinearForm(u*v*ds).Assemble()
[6]:
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.52440579389444
GMRes iteration 2, residual = 24.001710415059293
GMRes iteration 3, residual = 10.816186639702565
GMRes iteration 4, residual = 5.178501301182414
GMRes iteration 5, residual = 2.549268448878955
GMRes iteration 6, residual = 1.2888054956882689
GMRes iteration 7, residual = 0.6549832602491114
GMRes iteration 8, residual = 0.35541645583301723
GMRes iteration 9, residual = 0.19990866606606444
GMRes iteration 10, residual = 0.10836869993844767
GMRes iteration 11, residual = 0.05931445314039699
GMRes iteration 12, residual = 0.03294608123183388
GMRes iteration 13, residual = 0.013819139108246888
GMRes iteration 14, residual = 0.007360642470274841
GMRes iteration 15, residual = 0.003313810528174599
GMRes iteration 16, residual = 0.0019472886266694892
GMRes iteration 17, residual = 0.0011529608192671658
GMRes iteration 18, residual = 0.0006865451125338654
GMRes iteration 19, residual = 0.00040647668374399986
GMRes iteration 20, residual = 0.0002352530245081139
GMRes iteration 21, residual = 0.00012568335128557734
GMRes iteration 22, residual = 7.272844838705897e-05
GMRes iteration 23, residual = 4.282868528421661e-05
GMRes iteration 24, residual = 2.2389470959100374e-05
GMRes iteration 25, residual = 1.1323654081077149e-05
GMRes iteration 26, residual = 5.6817723197031886e-06
GMRes iteration 27, residual = 2.8154812159697703e-06
GMRes iteration 28, residual = 1.3918984915180408e-06
GMRes iteration 29, residual = 7.931632776571565e-07
GMRes iteration 30, residual = 4.5230612485297676e-07
GMRes iteration 31, residual = 2.72373496872173e-07
GMRes iteration 32, residual = 1.6096117668516758e-07
GMRes iteration 33, residual = 9.476709863742517e-08
GMRes iteration 34, residual = 5.2145026155054916e-08
GMRes iteration 35, residual = 2.9709338426878953e-08
GMRes iteration 36, residual = 1.7339940734525703e-08
GMRes iteration 37, residual = 9.167410459378509e-09
[8]:
Draw (gfu, order=5, min=-1, max=1);
prostprocessing on screen¶
[9]:
uscat = GridFunction(fes_screen)
with TaskManager(pajetrace=10**8):
# uscat.Set(1j*kappa*V.GetPotential(gfu)-K.GetPotential(gfu) , definedon=mesh.Boundaries("screen"))
# uscat.Set(HelmholtzCF(u*ds("sphere"), kappa)(gfu) , definedon=mesh.Boundaries("screen"))
uscat.Set(1j*kappa*HelmholtzSL(u*ds("sphere"),kappa)(gfu) - HelmholtzDL(u*ds("sphere"), kappa)(gfu), \
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 1h on Macbook Apple M4 Pro
[ ]: