.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/fields/electrodynamics/plot_pml_absorbing_boundary.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_api_gallery_fields_electrodynamics_plot_pml_absorbing_boundary.py: Berenger's Perfectly Matched Layer vs. a hard wall ======================================================= Jean-Pierre Berenger solved a problem that had limited FDTD simulations since Yee's original 1966 paper: a finite grid needs some boundary condition, and a simple wall reflects outgoing waves right back into the simulation. His Perfectly Matched Layer (PML) is a graded absorbing medium whose wave impedance matches the interior exactly, so outgoing waves are absorbed rather than reflected. :func:`~physicskit.fields.electrodynamics.pml_conductivity_profile` implements a simplified (non-split-field) approximation to this idea: it grades an ordinary electric conductivity :math:`\sigma(x)` smoothly up from zero over the outermost cells at each edge of the grid, so :math:`E_z` there obeys the lossy telegraph-style update of a conducting medium rather than the lossless Ampere's law, .. math:: \frac{\partial E_z}{\partial t} = \frac{1}{\varepsilon_0}\left(\frac{\partial H_y}{\partial x} - \sigma(x) E_z\right), instead of a hard electric wall (:math:`E_z=0`) that reflects everything outright. Comparing the two boundaries directly on the same launched pulse shows the dramatically smaller reflected echo the graded conductivity leaves behind. .. GENERATED FROM PYTHON SOURCE LINES 27-33 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from physicskit.fields import EPS0, MU0, courant_limit_1d, fdtd_1d, plot_field_1d, pml_conductivity_profile .. GENERATED FROM PYTHON SOURCE LINES 34-36 A pulse launched toward the right boundary of a finite grid ------------------------------------------------------------------ .. GENERATED FROM PYTHON SOURCE LINES 36-47 .. code-block:: Python N, dx = 500, 1e-3 dt = 0.99 * courant_limit_1d(dx) eta0 = np.sqrt(MU0 / EPS0) x0, sigma = 100, 10 Ez0 = np.exp(-((np.arange(N) - x0) ** 2) / (2 * sigma**2)) xh = np.arange(N - 1) + 0.5 Hy0 = -np.exp(-((xh - x0) ** 2) / (2 * sigma**2)) / eta0 # right-moving: Hy = -Ez/eta0 eps_r, mu_r = np.ones(N), np.ones(N) steps = 900 .. GENERATED FROM PYTHON SOURCE LINES 48-50 Compare a hard (PEC) wall against Berenger's graded-conductivity PML --------------------------------------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 50-55 .. code-block:: Python Ez_wall, _ = fdtd_1d(Ez0.copy(), Hy0.copy(), eps_r, mu_r, steps=steps, dt=dt, dx=dx) sigma_pml = pml_conductivity_profile(N, pml_width=120, dx=dx) Ez_pml, _ = fdtd_1d(Ez0.copy(), Hy0.copy(), eps_r, mu_r, steps=steps, dt=dt, dx=dx, sigma=sigma_pml) .. GENERATED FROM PYTHON SOURCE LINES 56-59 The PML leaves a far smaller reflected echo in the left half of the grid than the hard wall does -- the same graded-impedance-matching idea behind Berenger's original PML. .. GENERATED FROM PYTHON SOURCE LINES 59-72 .. code-block:: Python reflected_wall = np.max(np.abs(Ez_wall[: N // 2])) reflected_pml = np.max(np.abs(Ez_pml[: N // 2])) fig, ax = plot_field_1d(np.arange(N), Ez_wall, label="hard wall") plot_field_1d(np.arange(N), Ez_pml, ax=ax, label="PML") ax.set_title(f"reflected amplitude: wall={reflected_wall:.3f}, PML={reflected_pml:.3f}") fig.tight_layout() print(f"reflected amplitude, hard wall: {reflected_wall:.4f}") print(f"reflected amplitude, PML: {reflected_pml:.4f}") print(f"reduction factor: {reflected_wall / reflected_pml:.1f}x") .. image-sg:: /api/gallery/fields/electrodynamics/images/sphx_glr_plot_pml_absorbing_boundary_001.png :alt: reflected amplitude: wall=0.709, PML=0.072 :srcset: /api/gallery/fields/electrodynamics/images/sphx_glr_plot_pml_absorbing_boundary_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none reflected amplitude, hard wall: 0.7088 reflected amplitude, PML: 0.0717 reduction factor: 9.9x .. GENERATED FROM PYTHON SOURCE LINES 73-81 Space-time diagrams: the echo is a visible feature, not just a number -------------------------------------------------------------------------- Re-running :func:`~physicskit.fields.electrodynamics.fdtd_1d` in short chunks (feeding each chunk's output back in as the next chunk's initial condition) and stacking the intermediate ``Ez`` snapshots into an image shows the reflected echo directly: a second ridge peeling off the right wall and heading back left in the hard-wall panel, barely visible at all in the PML panel. .. GENERATED FROM PYTHON SOURCE LINES 81-110 .. code-block:: Python n_snap_steps = 15 n_snapshots = steps // n_snap_steps snap_times = np.arange(n_snapshots + 1) * n_snap_steps * dt def _snapshot_series(sigma_profile): Ez_s, Hy_s = Ez0.copy(), Hy0.copy() snaps = np.empty((n_snapshots + 1, N)) snaps[0] = Ez_s for i in range(n_snapshots): Ez_s, Hy_s = fdtd_1d(Ez_s, Hy_s, eps_r, mu_r, steps=n_snap_steps, dt=dt, dx=dx, sigma=sigma_profile) snaps[i + 1] = Ez_s return snaps snaps_wall = _snapshot_series(None) snaps_pml = _snapshot_series(sigma_pml) fig2, (ax_wall, ax_pml) = plt.subplots(1, 2, figsize=(10, 4), sharey=True) extent = (0, N * dx, snap_times[0], snap_times[-1]) vmax = max(np.abs(snaps_wall).max(), np.abs(snaps_pml).max()) for ax, snaps, title in ((ax_wall, snaps_wall, "hard wall"), (ax_pml, snaps_pml, "PML")): im = ax.imshow(snaps, extent=extent, origin="lower", aspect="auto", cmap="RdBu_r", vmin=-vmax, vmax=vmax) ax.set_xlabel("x") ax.set_title(title) ax_wall.set_ylabel("t") fig2.colorbar(im, ax=(ax_wall, ax_pml), label="Ez") fig2.suptitle("space-time diagrams: the hard wall's echo vs. the PML's near-total absorption") .. image-sg:: /api/gallery/fields/electrodynamics/images/sphx_glr_plot_pml_absorbing_boundary_002.png :alt: space-time diagrams: the hard wall's echo vs. the PML's near-total absorption, hard wall, PML :srcset: /api/gallery/fields/electrodynamics/images/sphx_glr_plot_pml_absorbing_boundary_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none Text(0.5, 0.98, "space-time diagrams: the hard wall's echo vs. the PML's near-total absorption") .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.089 seconds) .. _sphx_glr_download_api_gallery_fields_electrodynamics_plot_pml_absorbing_boundary.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_pml_absorbing_boundary.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_pml_absorbing_boundary.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_pml_absorbing_boundary.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_