Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
{
"cells": [
{
"cell_type": "markdown",
"id": "2fd77000",
"metadata": {},
"source": [
"# Discontinuous Galerkin for the Wave Equation\n",
"\n",
"We solve the first order wave equation by a matrix-free explicit DG method:\n",
"\n",
"\\begin{eqnarray*}\n",
"\\frac{\\partial p}{\\partial t} & = & \\operatorname{div} u \\\\\n",
"\\frac{\\partial u}{\\partial t} & = & \\nabla p\n",
"\\end{eqnarray*}\n",
"\n",
"\n",
"Using DG discretization in space we obtain the ODE system\n",
"\\begin{eqnarray*}\n",
"M_p \\dot{p} & = & -B^T u \\\\\n",
"M_u \\dot{u} & = & B p,\n",
"\\end{eqnarray*}\n",
"\n",
"with mass-matrices $M_p$ and $M_u$, and the discretization matrix $B$ for the gradient, and $-B^T$ for the divergence. \n",
"\n",
"\n",
"The DG bilinear-form for the gradient is:\n",
"\n",
"$$\n",
"b(p,v) = \\sum_{T}\n",
"\\Big\\{ \\int_T \\nabla p \\, v + \\int_{\\partial T} (\\{ p \\} - p) \\, v_n \\, ds \\Big\\},\n",
"$$\n",
"where $\\{ p \\}$ is the average of $p$ on the facet.\n",
"\n",
"The computational advantages of a proper version of DG is:\n",
"\n",
"* universal element-matrices for the differntial operator $B$\n",
"* cheaply invertible mass matrices (orthogonal polynomials, sum-factorization)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8b11665a",
"metadata": {},
"outputs": [],
"source": [
"from ngsolve import *\n",
"from netgen.occ import *\n",
"from time import time\n",
"\n",
"from ngsolve.webgui import Draw\n",
"from netgen.webgui import Draw as DrawGeo\n",
"\n",
"box = Box((-1,-1,-1), (1,1,0))\n",
"# sp = Sphere((0.5,0,0), 0.2)\n",
"disc = Cylinder( Axes((0.5,0,0), X, Y), r=0.4, h=0.2)\n",
"shape = box-disc\n",
"geo = OCCGeometry(shape)\n",
"\n",
"h = 0.1\n",
" \n",
"mesh = Mesh( geo.GenerateMesh(maxh=h))\n",
"mesh.Curve(3)\n",
"Draw(mesh);"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3dbda538",
"metadata": {},
"outputs": [],
"source": [
"order = 4\n",
"fes_p = L2(mesh, order=order, all_dofs_together=True)\n",
"fes_u = VectorL2(mesh, order=order, piola=True)\n",
"fes_tr = FacetFESpace(mesh, order=order)\n",
"\n",
"print (\"ndof_p = \", fes_p.ndof, \"+\", fes_tr.ndof, \", ndof_u =\", fes_u.ndof)\n",
"\n",
"traceop = fes_p.TraceOperator(fes_tr, average=True) \n",
"\n",
"gfu = GridFunction(fes_u)\n",
"gfp = GridFunction(fes_p)\n",
"gftr = GridFunction(fes_tr)\n",
"\n",
"gfp.Interpolate( exp(-400*(x**2+y**2+z**2)))\n",
"gftr.vec.data = traceop * gfp.vec"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1c19b6ce",
"metadata": {},
"outputs": [],
"source": [
"p = fes_p.TrialFunction()\n",
"v = fes_u.TestFunction()\n",
"phat = fes_tr.TrialFunction()\n",
"\n",
"n = specialcf.normal(mesh.dim)"
]
},
{
"cell_type": "markdown",
"id": "835e8a51",
"metadata": {},
"source": [
"$$\n",
"b(p,v) = \\sum_{T}\n",
"\\Big\\{ \\int_T \\nabla p \\, v + \\int_{\\partial T} (\\{ p \\} - p) \\, v_n \\, ds \\Big\\},\n",
"$$\n",
"\n",
"where $\\{ p \\}$ is the average of $p$ on the facet.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7903ef8f",
"metadata": {},
"outputs": [],
"source": [
"Bel = BilinearForm(trialspace=fes_p, testspace=fes_u, geom_free = True)\n",
"Bel += grad(p)*v * dx -p*(v*n) * dx(element_boundary=True)\n",
"Bel.Assemble()\n",
"\n",
"Btr = BilinearForm(trialspace=fes_tr, testspace=fes_u, geom_free = True)\n",
"Btr += phat * (v*n) *dx(element_boundary=True)\n",
"Btr.Assemble();\n",
"\n",
"B = Bel.mat + Btr.mat @ traceop"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3036f93d",
"metadata": {},
"outputs": [],
"source": [
"invmassp = fes_p.Mass(1).Inverse()\n",
"invmassu = fes_u.Mass(1).Inverse()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d49f6cff",
"metadata": {},
"outputs": [],
"source": [
"gfp.Interpolate( exp(-100*(x**2+y**2+z**2)))\n",
"gfu.vec[:] = 0\n",
"\n",
"scene = Draw (gftr, draw_vol=False, order=3);\n",
"\n",
"t = 0\n",
"dt = 0.3 * h / (order+1)**2 \n",
"tend = 1.2\n",
"\n",
"op1 = dt * invmassu @ B\n",
"op2 = dt * invmassp @ B.T\n",
"\n",
"cnt = 0\n",
"with TaskManager(): \n",
" while t < tend:\n",
" t = t+dt\n",
" gfu.vec.data += op1 * gfp.vec\n",
" gfp.vec.data -= op2 * gfu.vec\n",
" cnt = cnt+1\n",
" if cnt%10 == 0:\n",
" gftr.vec.data = traceop * gfp.vec\n",
" scene.Redraw()"
]
},
{
"cell_type": "markdown",
"id": "719e9c5e",
"metadata": {},
"source": [
"## Time-stepping on the device"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ca806f69",
"metadata": {},
"outputs": [],
"source": [
"try:\n",
" import ngsolve.ngscuda\n",
"except:\n",
" print (\"Sorry, no cuda device\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "33406cbb",
"metadata": {},
"outputs": [],
"source": [
"gfp.Interpolate( exp(-100*(x**2+y**2+z**2)))\n",
"gfu.vec[:] = 0\n",
"\n",
"scene = Draw (gftr, draw_vol=False, order=3);\n",
"\n",
"t = 0\n",
"dt = 0.5 * h / (order+1)**2 / 2\n",
"tend = 0.1\n",
"\n",
"op1 = (dt * invmassu @ B).CreateDeviceMatrix()\n",
"op2 = (dt * invmassp @ B.T).CreateDeviceMatrix()\n",
"\n",
"devu = gfu.vec.CreateDeviceVector(copy=True)\n",
"devp = gfp.vec.CreateDeviceVector(copy=True)\n",
"\n",
"cnt = 0\n",
"with TaskManager(): \n",
" while t < tend:\n",
" t = t+dt\n",
" devu += op1 * devp\n",
" devp -= op2 * devu\n",
" cnt = cnt+1\n",
" if cnt%10 == 0:\n",
" gfp.vec.data = devp\n",
" gftr.vec.data = traceop * gfp.vec\n",
" scene.Redraw()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "77281b6e",
"metadata": {},
"outputs": [],
"source": [
"print (op1.GetOperatorInfo())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "575aa7b0",
"metadata": {},
"outputs": [],
"source": [
"ts = time()\n",
"steps = 10\n",
"for i in range(steps):\n",
" devu += op1 * devp\n",
" devp -= op2 * devu\n",
"te = time()\n",
"print (\"ndof = \", gfp.space.ndof, \"+\", gfu.space.ndof, \", time per step =\", (te-ts)/steps)"
]
},
{
"cell_type": "markdown",
"id": "93f8f355",
"metadata": {},
"source": [
"On the A-100:\n",
"\n",
" ndof = 651035 + 1953105 , time per step = 0.0023579835891723634"
]
},
{
"cell_type": "markdown",
"id": "c176e930",
"metadata": {},
"source": [
"## Time-domain PML\n",
"\n",
"PML (perfectly matched layers) is a method for approximating outgoing waves on a truncated domain. Its time domain version leads to additional field variables in the PML region, which are coupled via time-derivatives only.\n",
"\n",
"Formulation of B. Kapidani, J. Schöberl, [arxiv](https://arxiv.org/abs/2002.08733)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "52a88f41",
"metadata": {},
"outputs": [],
"source": [
"# from ring_resonator_import import *\n",
"from ngsolve import *\n",
"from ngsolve.webgui import Draw"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "362613ed-ec18-40f6-87c9-3c12e437e017",
"metadata": {},
"outputs": [],
"source": [
"from netgen.geom2d import SplineGeometry\n",
"\n",
"geo = SplineGeometry()\n",
"\n",
"xneg =-0.43\n",
"xpos = 0.43\n",
"yneg =-0.48\n",
"ypos = 0.48\n",
"wslab = 0.04\n",
"cringx = 0.0\n",
"cringy = 0.0\n",
"rring = 0.4\n",
"gap = 0.005\n",
"\n",
"pntx = [xneg,xpos]\n",
"pnty = [yneg,-rring-gap-wslab,-rring-gap,rring+gap,rring+gap+wslab,ypos]\n",
"\n",
"pts = [geo.AddPoint(xi,yi) for yi in pnty for xi in pntx]\n",
"\n",
"### geometry #######################################################\n",
"geo.Append ([\"line\", pts[0], pts[1]], leftdomain=1, rightdomain=0)\n",
"geo.Append ([\"line\", pts[1], pts[3]], leftdomain=1, rightdomain=0)\n",
"geo.Append ([\"line\", pts[3], pts[2]], leftdomain=1, rightdomain=2)\n",
"geo.Append ([\"line\", pts[2], pts[0]], leftdomain=1, rightdomain=0)\n",
"\n",
"geo.Append ([\"line\", pts[3], pts[5]], leftdomain=2, rightdomain=0,bc=\"normal_wg_rightbottom\")\n",
"geo.Append ([\"line\", pts[5], pts[4]], leftdomain=2, rightdomain=3)\n",
"geo.Append ([\"line\", pts[4], pts[2]], leftdomain=2, rightdomain=0,bc=\"normal_wg_leftbottom\")\n",
"\n",
"geo.Append ([\"line\", pts[5], pts[7]], leftdomain=3, rightdomain=0)\n",
"geo.Append ([\"line\", pts[7], pts[6]], leftdomain=3, rightdomain=4)\n",
"geo.Append ([\"line\", pts[6], pts[4]], leftdomain=3, rightdomain=0)\n",
"\n",
"geo.Append ([\"line\", pts[7], pts[9]], leftdomain=4, rightdomain=0,bc=\"normal_wg_righttop\")\n",
"geo.Append ([\"line\", pts[9], pts[8]], leftdomain=4, rightdomain=5)\n",
"geo.Append ([\"line\", pts[8], pts[6]], leftdomain=4, rightdomain=0,bc=\"normal_wg_lefttop\")\n",
"\n",
"geo.Append ([\"line\", pts[9], pts[11]], leftdomain=5, rightdomain=0)\n",
"geo.Append ([\"line\", pts[11], pts[10]], leftdomain=5, rightdomain=0)\n",
"geo.Append ([\"line\", pts[10], pts[8]], leftdomain=5, rightdomain=0)\n",
"\n",
"geo.AddCircle(c=(cringx,cringy), r=rring, leftdomain=6, rightdomain=3)\n",
"geo.AddCircle(c=(cringx,cringy), r=rring-wslab, leftdomain=7, rightdomain=6)\n",
"\n",
"for i in (1,3,5,7):\n",
" geo.SetMaterial(i, \"air\")\n",
"for i in (2,4,6):\n",
" geo.SetMaterial(i, \"eps_nine\")\n",
"data = geo.CreatePML(0.05)\n",
"normals = data[\"normals\"]\n",
"\n",
"\n",
"mesh = Mesh(geo.GenerateMesh(maxh=0.05))\n",
"\n",
"eps_r = {\"air\" : 1, \"eps_nine\" : 3**3}\n",
"\n",
"for mat in mesh.GetMaterials():\n",
" if mat.startswith(\"pml_normal_wg\"):\n",
" eps_r[mat] = eps_r[\"eps_nine\"]\n",
"\n",
"for mat in mesh.GetMaterials():\n",
" if mat not in eps_r:\n",
" eps_r[mat] = eps_r[\"air\"]\n",
"\n",
"### Parameters for Source field ######\n",
"wavelength = 1.542\n",
"fcen = 5/wavelength\n",
"df = 0.1\n",
"tpeak = 1\n",
"order = 3\n",
"\n",
"mesh.Curve(order)\n",
"fes_facet = FacetFESpace(mesh, order=order+1)\n",
"gfsource = GridFunction(fes_facet)\n",
"\n",
"source_cf = sin( (pi/wslab)*(y-pnty[3]) ) \n",
"gfsource.Set(source_cf,definedon=mesh.Boundaries(\"normal_wg_lefttop\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "41a7b803",
"metadata": {},
"outputs": [],
"source": [
"fes_u = VectorL2(mesh, order=order, piola=True, order_policy=ORDER_POLICY.CONSTANT)\n",
"fes_p = L2(mesh, order=order+1, all_dofs_together=True, order_policy=ORDER_POLICY.CONSTANT)\n",
"fes_tr = FacetFESpace(mesh, order=order+1)\n",
"fes_hdiv = HDiv(mesh, order=order+1, orderinner=1)\n",
"\n",
"n = specialcf.normal(2) \n",
"\n",
"p,q = fes_p.TnT()\n",
"u,v = fes_u.TnT()\n",
"ptr,qtr = fes_tr.TnT()\n",
"uhdiv,vhdiv = fes_hdiv.TnT()\n",
"\n",
"Bel = BilinearForm(grad(p)*v*dx - p*(v*n)*dx(element_boundary=True), geom_free=True).Assemble()\n",
"Btr = BilinearForm(0.5*ptr*(n*v)*dx(element_boundary=True), geom_free=True).Assemble()\n",
"Bstab = BilinearForm(p*(vhdiv*n)*dx(element_boundary=True), geom_free=True).Assemble()\n",
"\n",
"\n",
"nvec = { mat : ((normals[mat][0], normals[mat][1]) if mat in normals else (0,0)) for mat in mesh.GetMaterials() }\n",
"\n",
"cfn = CF( [CF(nvec[mat]) for mat in mesh.GetMaterials()])\n",
"cft = CF( ( cfn[1], -cfn[0] ) )\n",
"\n",
"pml1d = mesh.Materials(\"pml_default.*|pml_normal.*\")\n",
"eps = CF([eps_r[mat] for mat in mesh.GetMaterials()])\n",
"\n",
"\n",
"fes = fes_p*fes_p*fes_u*fes_u*fes_hdiv\n",
"emb_p, emb_phat, emb_u, emb_uhat, emb_hdiv = fes.embeddings\n",
"\n",
"# gradient operator\n",
"traceop = fes_p.TraceOperator(fes_tr, False)\n",
"fullB = emb_u @ (Bel.mat + Btr.mat @ traceop) @ emb_p.T + emb_hdiv@Bstab.mat@emb_p.T\n",
"\n",
"# mass matrices\n",
"invmassp = fes_p.Mass(eps).Inverse()\n",
"invmassu = fes_u.Mass(Id(mesh.dim)).Inverse()\n",
"Mstab = BilinearForm(uhdiv*vhdiv*dx, diagonal=True).Assemble()\n",
"Mstabinv = Mstab.mat.Inverse()\n",
"\n",
"\n",
"invp = emb_p @ invmassp @ emb_p.T + emb_phat @ invmassp @ emb_phat.T\n",
"invu = emb_u @ invmassu @ emb_u.T + emb_uhat @ invmassu @ emb_uhat.T + emb_hdiv@Mstabinv@emb_hdiv.T\n",
"\n",
"\n",
"# damping matrices\n",
"dampp1 = fes_p.Mass (eps, definedon=pml1d)\n",
"dampp2 = fes_p.Mass (eps, definedon=mesh.Materials(\"pml_corner\"))\n",
"dampu1 = fes_u.Mass (OuterProduct(cfn,cfn), definedon=pml1d)\n",
"dampu2 = fes_u.Mass (OuterProduct(cft,cft), definedon=pml1d)\n",
"\n",
"dampingu = emb_u @ dampu1 @ emb_u.T + (-emb_u + emb_uhat) @ dampu2 @ (emb_u.T + emb_uhat.T)\n",
"dampingp = emb_p @ dampp1 @ emb_p.T + emb_p @ dampp2 @ (2*emb_p.T-emb_phat.T) + emb_phat @ dampp2 @ emb_p.T\n",
"\n",
"\n",
"# source term\n",
"Lsrc = LinearForm(gfsource*q*dx(element_boundary=True)).Assemble()\n",
"srcvec = emb_p * (invmassp*Lsrc.vec).Evaluate()\n",
"\n",
"# time-envelope:\n",
"def Envelope(t):\n",
" if abs((t-tpeak)/tpeak) < 1:\n",
" return (2*exp(1)/sqrt(pi))*sin(2*pi*fcen*t)*exp (-1/(1-((t-tpeak)/tpeak)**2))\n",
" else:\n",
" return 0"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "369555b1",
"metadata": {},
"outputs": [],
"source": [
"gfu = GridFunction(fes)\n",
"scene = Draw (gfu.components[0], order=3, min=-0.05, max=0.05, autoscale=False)\n",
"\n",
"t = 0\n",
"tend = 12\n",
"tau = 2e-4\n",
"i = 0\n",
"sigma = 10 # pml damping parameter\n",
"\n",
"op1 = invp@(-fullB.T-sigma*dampingp) \n",
"op2 = invu@(fullB-sigma*dampingu)\n",
"with TaskManager(): \n",
" while t < tend:\n",
"\n",
" gfu.vec.data += tau*Envelope(t)*srcvec\n",
" gfu.vec.data += tau*op1*gfu.vec\n",
" gfu.vec.data += tau*op2*gfu.vec \n",
"\n",
" t += tau\n",
" i += 1\n",
" if i%20 == 0: scene.Redraw()"
]
},
{
"cell_type": "markdown",
"id": "3af4e308",
"metadata": {},
"source": [
"The differential operators and coupling terms to the pml - variables are represented via linear operators;"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ff4cb3ee",
"metadata": {},
"outputs": [],
"source": [
"print (fullB.GetOperatorInfo())\n",
"print (dampingp.GetOperatorInfo())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "94737b9b",
"metadata": {},
"outputs": [],
"source": [
"print (op1.GetOperatorInfo())"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f0d9314a-79eb-45fc-91b1-506a41c33277",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "3fdeb9fc-a372-43ff-b071-accb954e8dd1",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
4426a015fThis file is pinned to the selected release. Download the original to open it in your design tool.