{ "cells": [ { "cell_type": "markdown", "id": "3e4d4e4c", "metadata": { "papermill": { "duration": 0.00139, "end_time": "2026-05-27T20:00:37.159118+00:00", "exception": false, "start_time": "2026-05-27T20:00:37.157728+00:00", "status": "completed" }, "tags": [] }, "source": [ "# Hollow Rectangular Waveguide Modes\n", "\n", "This notebook solves a PEC rectangular waveguide with `WaveguideModeSolver`, compares against analytic TE/TM modes, and plots the first fields." ] }, { "cell_type": "code", "execution_count": 1, "id": "bfef1c6d", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:00:37.165276Z", "iopub.status.busy": "2026-05-27T20:00:37.165099Z", "iopub.status.idle": "2026-05-27T20:00:37.896231Z", "shell.execute_reply": "2026-05-27T20:00:37.895588Z" }, "papermill": { "duration": 0.733829, "end_time": "2026-05-27T20:00:37.897013+00:00", "exception": false, "start_time": "2026-05-27T20:00:37.163184+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "import palacetoolkit as ptk\n", "\n", "import gmsh\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "from palacetoolkit.mode_solver import WaveguideModeSolver\n", "from palacetoolkit.utils import write_and_finalize_gmsh\n", "from palacetoolkit.viz import view_mesh\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "902f3519", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:00:37.903124Z", "iopub.status.busy": "2026-05-27T20:00:37.902866Z", "iopub.status.idle": "2026-05-27T20:00:37.908380Z", "shell.execute_reply": "2026-05-27T20:00:37.907930Z" }, "papermill": { "duration": 0.010789, "end_time": "2026-05-27T20:00:37.909040+00:00", "exception": false, "start_time": "2026-05-27T20:00:37.898251+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "def _set_transfinite_rect(surf_tag, nx, ny):\n", " bnd = gmsh.model.getBoundary([(2, surf_tag)], oriented=True)\n", " lines = [abs(t) for _, t in bnd]\n", " for line in lines:\n", " pts = gmsh.model.getBoundary([(1, line)], oriented=False)\n", " c0 = gmsh.model.getValue(0, pts[0][1], [])\n", " c1 = gmsh.model.getValue(0, pts[1][1], [])\n", " dx = abs(c1[0] - c0[0])\n", " dy = abs(c1[1] - c0[1])\n", " n = (nx + 1) if dx > dy else (ny + 1)\n", " gmsh.model.mesh.setTransfiniteCurve(line, n)\n", " gmsh.model.mesh.setTransfiniteSurface(surf_tag)\n", "\n", "\n", "def make_rectangular_mesh(a, b, nx, ny, structured=True, lc=None, filename=None):\n", " gmsh.initialize()\n", " gmsh.option.setNumber(\"General.Verbosity\", 0)\n", " gmsh.model.add(\"hollow_waveguide\")\n", "\n", " gmsh.model.occ.addRectangle(0, 0, 0, a, b, tag=1)\n", " gmsh.model.occ.synchronize()\n", "\n", " gmsh.model.addPhysicalGroup(2, [1], tag=1, name=\"domain\")\n", " bnd = gmsh.model.getBoundary([(2, 1)], oriented=False)\n", " bnd_tags = [abs(t) for _, t in bnd]\n", " gmsh.model.addPhysicalGroup(1, bnd_tags, tag=1, name=\"PEC\")\n", "\n", " if structured:\n", " _set_transfinite_rect(1, nx, ny)\n", " gmsh.model.mesh.setRecombine(2, 1)\n", " else:\n", " _lc = lc if lc is not None else max(a / nx, b / ny)\n", " gmsh.option.setNumber(\"Mesh.CharacteristicLengthMin\", 0.8 * _lc)\n", " gmsh.option.setNumber(\"Mesh.CharacteristicLengthMax\", 1.2 * _lc)\n", "\n", " gmsh.model.mesh.generate(2)\n", " return write_and_finalize_gmsh(filename, prefix=\"wg_rect_\")" ] }, { "cell_type": "code", "execution_count": 3, "id": "ae6533ee", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:00:37.911957Z", "iopub.status.busy": "2026-05-27T20:00:37.911783Z", "iopub.status.idle": "2026-05-27T20:00:37.915400Z", "shell.execute_reply": "2026-05-27T20:00:37.914917Z" }, "papermill": { "duration": 0.005726, "end_time": "2026-05-27T20:00:37.915940+00:00", "exception": false, "start_time": "2026-05-27T20:00:37.910214+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "def analytic_kn(a, b, omega, m_max=5, n_max=5, mu=1.0, eps=1.0):\n", " modes = []\n", " k0_sq = omega**2 * mu * eps\n", "\n", " for m in range(0, m_max + 1):\n", " for n in range(0, n_max + 1):\n", " if m == 0 and n == 0:\n", " continue\n", " kc_sq = (m * np.pi / a) ** 2 + (n * np.pi / b) ** 2\n", " kn = np.sqrt((k0_sq - kc_sq) + 0j)\n", " modes.append((f\"TE{m}{n}\", np.sqrt(kc_sq), kn))\n", "\n", " for m in range(1, m_max + 1):\n", " for n in range(1, n_max + 1):\n", " kc_sq = (m * np.pi / a) ** 2 + (n * np.pi / b) ** 2\n", " kn = np.sqrt((k0_sq - kc_sq) + 0j)\n", " modes.append((f\"TM{m}{n}\", np.sqrt(kc_sq), kn))\n", "\n", " modes.sort(key=lambda x: -x[2].real)\n", " return modes" ] }, { "cell_type": "code", "execution_count": 4, "id": "3be79dcc", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:00:37.918523Z", "iopub.status.busy": "2026-05-27T20:00:37.918405Z", "iopub.status.idle": "2026-05-27T20:00:37.922021Z", "shell.execute_reply": "2026-05-27T20:00:37.921450Z" }, "papermill": { "duration": 0.005489, "end_time": "2026-05-27T20:00:37.922505+00:00", "exception": false, "start_time": "2026-05-27T20:00:37.917016+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Top 8 analytic modes:\n", " TE10 : kc= 1.5708, kn= +5.268611 +0.000000j\n", " TE01 : kc= 3.1416, kn= +4.511769 +0.000000j\n", " TE20 : kc= 3.1416, kn= +4.511769 +0.000000j\n", " TE11 : kc= 3.5124, kn= +4.229499 +0.000000j\n", " TM11 : kc= 3.5124, kn= +4.229499 +0.000000j\n", " TE21 : kc= 4.4429, kn= +3.238280 +0.000000j\n", " TM21 : kc= 4.4429, kn= +3.238280 +0.000000j\n", " TE30 : kc= 4.7124, kn= +2.831793 +0.000000j\n" ] } ], "source": [ "a, b = 2.0, 1.0\n", "mu, eps = 1.0, 1.0\n", "c0 = 1.0 / np.sqrt(mu * eps)\n", "\n", "fc_te10 = c0 * np.pi / a / (2 * np.pi)\n", "f_op = 3.5 * fc_te10\n", "omega = 2 * np.pi * f_op\n", "\n", "analytic = analytic_kn(a, b, omega, m_max=4, n_max=4, mu=mu, eps=eps)\n", "print(\"Top 8 analytic modes:\")\n", "for name, kc, kn in analytic[:8]:\n", " print(f\" {name:6s}: kc={kc:8.4f}, kn={kn.real:+10.6f}{kn.imag:+10.6f}j\")" ] }, { "cell_type": "code", "execution_count": 5, "id": "3b2cd9cd", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:00:37.925186Z", "iopub.status.busy": "2026-05-27T20:00:37.925066Z", "iopub.status.idle": "2026-05-27T20:00:39.023255Z", "shell.execute_reply": "2026-05-27T20:00:39.022898Z" }, "papermill": { "duration": 1.101843, "end_time": "2026-05-27T20:00:39.025494+00:00", "exception": false, "start_time": "2026-05-27T20:00:37.923651+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Loading mesh file: /tmp/wg_rect_mhlsva3w.msh\n", "Groups to render transparent: ['air_none', 'air_plastic_enclosure']\n", "\n", "Mesh loaded successfully with 2 cell blocks\n", "Found 1024 triangles total\n", "Physical group tags in mesh: {1: 'domain'}\n" ] }, { "data": { "text/html": [ "
" ], "text/plain": [ "