{ "cells": [ { "cell_type": "markdown", "id": "e216b98f", "metadata": { "papermill": { "duration": 0.002166, "end_time": "2026-05-27T20:02:34.365166+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.363000+00:00", "status": "completed" }, "tags": [] }, "source": [ "# Waveguide box\n", "\n", "Simple elongated box waveguide mesh with two waveports.\n", "\n", "Generates a rectangular waveguide (elongated box) where:\n", "- The two end faces are labeled \"waveport_1\" and \"waveport_2\"\n", "- The four lateral surfaces are labeled \"metal\"\n", "\n", "Our goal is to measure the s parameters." ] }, { "cell_type": "code", "execution_count": 1, "id": "a2184d13", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:02:34.371816Z", "iopub.status.busy": "2026-05-27T20:02:34.371629Z", "iopub.status.idle": "2026-05-27T20:02:34.741536Z", "shell.execute_reply": "2026-05-27T20:02:34.740958Z" }, "papermill": { "duration": 0.373195, "end_time": "2026-05-27T20:02:34.742494+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.369299+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "import gmsh\n", "import math\n", "import os\n", "import sys\n", "from pathlib import Path\n", "\n", "from palacetoolkit.viz import view_mesh\n", "from palacetoolkit.geometry import extract_tag, xmin, xmax, ymin, ymax, zmin, zmax\n", "from palacetoolkit.mesh import refine_near_surfaces\n", "from palacetoolkit.simulation import Simulation, run_palace" ] }, { "cell_type": "markdown", "id": "9805464a", "metadata": { "papermill": { "duration": 0.003947, "end_time": "2026-05-27T20:02:34.748151+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.744204+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Parameters\n", "- filename : Output mesh filename\n", "- width : width of the waveguide in meters\n", "- height : height of the waveguide in meters\n", "- length : length of the waveguide in meters" ] }, { "cell_type": "code", "execution_count": 2, "id": "c27265c6", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:02:34.752273Z", "iopub.status.busy": "2026-05-27T20:02:34.751991Z", "iopub.status.idle": "2026-05-27T20:02:34.754840Z", "shell.execute_reply": "2026-05-27T20:02:34.754354Z" }, "papermill": { "duration": 0.005714, "end_time": "2026-05-27T20:02:34.755497+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.749783+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "filename=\"waveguide_box.msh\"\n", "\n", "# Default dimensions of the waveguide box (wr-90 standard)\n", "width=22.86e-3 \n", "height=10.16e-3 \n", "length=100e-3 " ] }, { "cell_type": "markdown", "id": "2fc8f9cf", "metadata": { "papermill": { "duration": 0.001371, "end_time": "2026-05-27T20:02:34.758590+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.757219+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Initialization of the model" ] }, { "cell_type": "code", "execution_count": 3, "id": "0f9278fa", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:02:34.762272Z", "iopub.status.busy": "2026-05-27T20:02:34.762116Z", "iopub.status.idle": "2026-05-27T20:02:34.765354Z", "shell.execute_reply": "2026-05-27T20:02:34.764948Z" }, "papermill": { "duration": 0.005903, "end_time": "2026-05-27T20:02:34.765916+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.760013+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "gmsh.initialize()\n", "gmsh.model.add(\"waveguide_box\")\n", "kernel = gmsh.model.occ" ] }, { "cell_type": "markdown", "id": "0a892f96", "metadata": { "papermill": { "duration": 0.001325, "end_time": "2026-05-27T20:02:34.768759+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.767434+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Geometry definition" ] }, { "cell_type": "code", "execution_count": 4, "id": "fa41cbdd", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:02:34.772148Z", "iopub.status.busy": "2026-05-27T20:02:34.772008Z", "iopub.status.idle": "2026-05-27T20:02:34.774974Z", "shell.execute_reply": "2026-05-27T20:02:34.774470Z" }, "papermill": { "duration": 0.005294, "end_time": "2026-05-27T20:02:34.775403+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.770109+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "# Create an elongated box centered at the origin\n", "\n", "# addBox(x, y, z, dx, dy, dz) — (x,y,z) is the corner\n", "box = kernel.addBox(\n", " -width / 2, -height / 2, 0,\n", " width, height, length,\n", ")\n", "\n", "kernel.synchronize()" ] }, { "cell_type": "markdown", "id": "c4e6aa04", "metadata": { "papermill": { "duration": 0.001355, "end_time": "2026-05-27T20:02:34.778449+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.777094+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Identifying Geometric Entities and Domains" ] }, { "cell_type": "code", "execution_count": 5, "id": "5df9a4aa", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:02:34.781991Z", "iopub.status.busy": "2026-05-27T20:02:34.781831Z", "iopub.status.idle": "2026-05-27T20:02:34.785532Z", "shell.execute_reply": "2026-05-27T20:02:34.785127Z" }, "papermill": { "duration": 0.00622, "end_time": "2026-05-27T20:02:34.786041+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.779821+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "# Identify surfaces by their bounding box positions\n", "all_surfaces = gmsh.model.getEntities(2)\n", "\n", "waveport_1_tags = [] # face at z = 0\n", "waveport_2_tags = [] # face at z = length\n", "metal_tags = [] # the four lateral faces\n", "\n", "eps = 1e-6\n", "\n", "for dimtag in all_surfaces:\n", "\n", " if abs(zmin(dimtag) - 0.0) < eps and abs(zmax(dimtag) - 0.0) < eps:\n", " waveport_1_tags.append(dimtag)\n", " elif abs(zmin(dimtag) - length) < eps and abs(zmax(dimtag) - length) < eps:\n", " waveport_2_tags.append(dimtag)\n", " else:\n", " metal_tags.append(dimtag)\n", "\n", "assert len(waveport_1_tags) == 1, f\"Expected 1 waveport_1 face, found {len(waveport_1_tags)}\"\n", "assert len(waveport_2_tags) == 1, f\"Expected 1 waveport_2 face, found {len(waveport_2_tags)}\"\n", "assert len(metal_tags) == 4, f\"Expected 4 metal faces, found {len(metal_tags)}\"" ] }, { "cell_type": "markdown", "id": "04bc34a5", "metadata": { "papermill": { "duration": 0.00136, "end_time": "2026-05-27T20:02:34.788919+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.787559+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Defining Physical Groups\n", "To prepare the geometry for export to Palace, we must define \"Physical Groups.\" These groups serve as labels that the solver uses to identify boundaries (surfaces) and domains (volumes) for applying physics settings, such as excitation ports or material properties." ] }, { "cell_type": "code", "execution_count": 6, "id": "cdc7ab2c", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:02:34.792267Z", "iopub.status.busy": "2026-05-27T20:02:34.792146Z", "iopub.status.idle": "2026-05-27T20:02:34.795264Z", "shell.execute_reply": "2026-05-27T20:02:34.794877Z" }, "papermill": { "duration": 0.005468, "end_time": "2026-05-27T20:02:34.795748+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.790280+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "# Physical groups (these become boundary attributes in Palace).\n", "# Use deterministic IDs so generated configs are stable and match the reference JSON.\n", "pg_waveport_1 = gmsh.model.addPhysicalGroup(2, [x[1] for x in waveport_1_tags], 1, name=\"waveport_1\")\n", "pg_waveport_2 = gmsh.model.addPhysicalGroup(2, [x[1] for x in waveport_2_tags], 2, name=\"waveport_2\")\n", "pg_metal = gmsh.model.addPhysicalGroup(2, [x[1] for x in metal_tags], 3, name=\"metal\")\n", "\n", "# Volume physical group\n", "all_volumes = gmsh.model.getEntities(3)\n", "vol_tags = [tag for _, tag in all_volumes]\n", "pg_volume = gmsh.model.addPhysicalGroup(3, vol_tags, 4, name=\"waveguide_volume\")\n", "\n", "# Map physical group names to their tags for later use.\n", "pg_map = {\n", " \"waveport_1\": pg_waveport_1,\n", " \"waveport_2\": pg_waveport_2,\n", " \"metal\": pg_metal,\n", " \"volume\": pg_volume\n", "}\n", "\n", "assert pg_map == {\"waveport_1\": 1, \"waveport_2\": 2, \"metal\": 3, \"volume\": 4}" ] }, { "cell_type": "markdown", "id": "0f2368d3", "metadata": { "papermill": { "duration": 0.001388, "end_time": "2026-05-27T20:02:34.798583+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.797195+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Mesh Generation and Export\n", "Next, we define the mesh resolution based on our operating frequency (10 GHz) and generate the final mesh for the Palace solver.\n", "\n", "- Refinement: We ensure higher mesh density near the waveports to capture electromagnetic behavior accurately.\n", "- Settings: We use the Frontal-Delaunay algorithm and set the mesh to first-order elements.\n", "- Export: The mesh is saved in the Gmsh 2.2 ASCII format, which is required for compatibility with Palace." ] }, { "cell_type": "code", "execution_count": 7, "id": "66e29ac7", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:02:34.801956Z", "iopub.status.busy": "2026-05-27T20:02:34.801810Z", "iopub.status.idle": "2026-05-27T20:02:35.605473Z", "shell.execute_reply": "2026-05-27T20:02:35.604885Z" }, "papermill": { "duration": 0.816578, "end_time": "2026-05-27T20:02:35.616506+00:00", "exception": false, "start_time": "2026-05-27T20:02:34.799928+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " ppw_near=20 ppw_far=10\n", " SizeMax=0.0030 transition=0.0075\n", " global: 8 curves, SizeMin=0.0015\n", "Info : Meshing 1D...\n", "Info : [ 0%] Meshing curve 1 (Line)\n", "Info : [ 10%] Meshing curve 2 (Line)\n", "Info : [ 20%] Meshing curve 3 (Line)\n", "Info : [ 30%] Meshing curve 4 (Line)\n", "Info : [ 40%] Meshing curve 5 (Line)\n", "Info : [ 50%] Meshing curve 6 (Line)\n", "Info : [ 60%] Meshing curve 7 (Line)\n", "Info : [ 60%] Meshing curve 8 (Line)\n", "Info : [ 70%] Meshing curve 9 (Line)\n", "Info : [ 80%] Meshing curve 10 (Line)\n", "Info : [ 90%] Meshing curve 11 (Line)\n", "Info : [100%] Meshing curve 12 (Line)\n", "Info : Done meshing 1D (Wall 0.0374193s, CPU 0.037833s)\n", "Info : Meshing 2D...\n", "Info : [ 0%] Meshing surface 1 (Plane, Frontal-Delaunay)\n", "Info : [ 20%] Meshing surface 2 (Plane, Frontal-Delaunay)\n", "Info : [ 40%] Meshing surface 3 (Plane, Frontal-Delaunay)\n", "Info : [ 60%] Meshing surface 4 (Plane, Frontal-Delaunay)\n", "Info : [ 70%] Meshing surface 5 (Plane, Frontal-Delaunay)\n", "Info : [ 90%] Meshing surface 6 (Plane, Frontal-Delaunay)\n", "Info : Done meshing 2D (Wall 0.0184283s, CPU 0.018458s)\n", "Info : Meshing 3D...\n", "Info : 3D Meshing 1 volume with 1 connected component\n", "Info : Tetrahedrizing 1266 nodes...\n", "Info : Done tetrahedrizing 1274 nodes (Wall 0.00834981s, CPU 0.007382s)\n", "Info : Reconstructing mesh...\n", "Info : - Creating surface mesh\n", "Info : - Identifying boundary edges\n", "Info : - Recovering boundary\n", "Info : Done reconstructing mesh (Wall 0.0181882s, CPU 0.013253s)\n", "Info : Found volume 1\n", "Info : It. 0 - 0 nodes created - worst tet radius 2.00763 (nodes removed 0 0)\n", "Info : 3D refinement terminated (1649 nodes total):\n", "Info : - 0 Delaunay cavities modified for star shapeness\n", "Info : - 0 nodes could not be inserted\n", "Info : - 6009 tetrahedra created in 0.010736 sec. (559703 tets/s)\n", "Info : 0 node relocations\n", "Info : Done meshing 3D (Wall 0.0399752s, CPU 0.033199s)\n", "Info : Optimizing mesh...\n", "Info : Optimizing volume 1\n", "Info : Optimization starts (volume = 2.32258e-05) with worst = 0.0117629 / average = 0.761057:\n", "Info : 0.00 < quality < 0.10 : 31 elements\n", "Info : 0.10 < quality < 0.20 : 48 elements\n", "Info : 0.20 < quality < 0.30 : 84 elements\n", "Info : 0.30 < quality < 0.40 : 82 elements\n", "Info : 0.40 < quality < 0.50 : 132 elements\n", "Info : 0.50 < quality < 0.60 : 293 elements\n", "Info : 0.60 < quality < 0.70 : 918 elements\n", "Info : 0.70 < quality < 0.80 : 1658 elements\n", "Info : 0.80 < quality < 0.90 : 1726 elements\n", "Info : 0.90 < quality < 1.00 : 1037 elements\n", "Info : 159 edge swaps, 2 node relocations (volume = 2.32258e-05): worst = 0.248964 / average = 0.777845 (Wall 0.00127162s, CPU 0.001314s)\n", "Info : 161 edge swaps, 2 node relocations (volume = 2.32258e-05): worst = 0.300339 / average = 0.778112 (Wall 0.00153182s, CPU 0.00159s)\n", "Info : No ill-shaped tets in the mesh :-)\n", "Info : 0.00 < quality < 0.10 : 0 elements\n", "Info : 0.10 < quality < 0.20 : 0 elements\n", "Info : 0.20 < quality < 0.30 : 0 elements\n", "Info : 0.30 < quality < 0.40 : 82 elements\n", "Info : 0.40 < quality < 0.50 : 125 elements\n", "Info : 0.50 < quality < 0.60 : 293 elements\n", "Info : 0.60 < quality < 0.70 : 916 elements\n", "Info : 0.70 < quality < 0.80 : 1643 elements\n", "Info : 0.80 < quality < 0.90 : 1763 elements\n", "Info : 0.90 < quality < 1.00 : 1041 elements\n", "Info : Done optimizing mesh (Wall 0.00429291s, CPU 0.00431s)\n", "Info : 1649 nodes 8635 elements\n", "Info : Writing '/home/martin/Desktop/PalaceToolkit/docs/examples/waveguide_box.msh'...\n", "Info : Done writing '/home/martin/Desktop/PalaceToolkit/docs/examples/waveguide_box.msh'\n", "Loading mesh file: waveguide_box.msh\n", "Groups to render transparent: ['air_none', 'air_plastic_enclosure']\n", "\n", "Mesh loaded successfully with 2 cell blocks\n", "Found 2528 triangles total\n", "Physical group tags in mesh: {1: 'waveport_1', 2: 'waveport_2', 3: 'metal'}\n" ] }, { "data": { "text/html": [ "
" ], "text/plain": [ "