{ "cells": [ { "cell_type": "markdown", "id": "50ad7e94", "metadata": { "papermill": { "duration": 0.003544, "end_time": "2026-05-26T01:16:56.938421+00:00", "exception": false, "start_time": "2026-05-26T01:16:56.934877+00:00", "status": "completed" }, "tags": [] }, "source": [ "## Coax to waveguide\n", "This notebook outlines the design and simulation workflow for a horn antenna fed by a standard WR-90 waveguide operating at a target frequency of 10 GHz (λ≈30mm)\n", "### Design Parameters \n", "The antenna geometry and probe feed are defined based on the following physical constraints:\n", "\n", "Waveguide (WR-90): \n", "- 22.86 mm (width) \n", "- 10.16 mm (height) \n", "- 40 mm (length)\n", "\n", "Probe Feed:\n", "- Probe Length: 5.89 mm (≈λ/5) to ensure optimal impedance matching.\n", "- Coaxial Geometry: 3.6 mm (outer diameter) and 1.28 mm (inner diameter).\n", "\n", "These parameters serve as the foundation for our geometric construction and subsequent discretization, ensuring the antenna is tuned for its intended frequency of operation." ] }, { "cell_type": "code", "execution_count": 1, "id": "afd2e839", "metadata": { "execution": { "iopub.execute_input": "2026-05-26T01:16:56.948145Z", "iopub.status.busy": "2026-05-26T01:16:56.947906Z", "iopub.status.idle": "2026-05-26T01:16:57.770452Z", "shell.execute_reply": "2026-05-26T01:16:57.768854Z" }, "papermill": { "duration": 0.830005, "end_time": "2026-05-26T01:16:57.771349+00:00", "exception": false, "start_time": "2026-05-26T01:16:56.941344+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "import gmsh\n", "import math\n", "import os\n", "import json\n", "\n", "from palacetoolkit.viz import run_with_scrollable_output, 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.viz import view_mesh\n", "from palacetoolkit.mesh import (\n", " refine_near_surfaces\n", ")" ] }, { "cell_type": "markdown", "id": "e0d257be", "metadata": { "papermill": { "duration": 0.003879, "end_time": "2026-05-26T01:16:57.778153+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.774274+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Parameters:\n", "- inner_diameter_mm: Inner diameter of the coaxial cable in millimeters.\n", "- outer_diameter_mm: Outer diameter of the coaxial cable in millimeters.\n", "- probe_length_mm : Length of the probe in milimiters.\n", "- length_mm: Length of the coaxial cable section in millimeters.\n", "- wg_height: Height of the rectangular waveguide in millimeters.\n", "- wg_length: Length of the rectangular waveguide in millimeters.\n", "- wg_width: Width of the rectangular waveguide in millimeters.\n", "- freq_ghz: Frequency of the wave in gigahertz.\n", "- verbose: Verbosity level for Gmsh output\n", "- filename: Name of the output mesh file." ] }, { "cell_type": "code", "execution_count": 2, "id": "8e484ad2", "metadata": { "execution": { "iopub.execute_input": "2026-05-26T01:16:57.786562Z", "iopub.status.busy": "2026-05-26T01:16:57.786254Z", "iopub.status.idle": "2026-05-26T01:16:57.792115Z", "shell.execute_reply": "2026-05-26T01:16:57.790339Z" }, "papermill": { "duration": 0.011665, "end_time": "2026-05-26T01:16:57.793384+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.781719+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "inner_diameter_mm: float = 1.28\n", "outer_diameter_mm: float = 3.6 \n", "probe_length_mm = 5.89\n", "length_mm: float = 5\n", "wg_height: float = 10.16\n", "wg_length: float = 40\n", "wg_width: float = 22.86\n", "freq_ghz: float = 10.0\n", "verbose: int = 2\n", "filename: str = \"coax_to_waveguide.msh\"\n", "mesh_order = 1\n", "gui = False\n", "order = 1" ] }, { "cell_type": "markdown", "id": "2dfa8e99", "metadata": { "papermill": { "duration": 0.003325, "end_time": "2026-05-26T01:16:57.800449+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.797124+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Initializing the Modeling Environment" ] }, { "cell_type": "code", "execution_count": 3, "id": "83f6e661", "metadata": { "execution": { "iopub.execute_input": "2026-05-26T01:16:57.806641Z", "iopub.status.busy": "2026-05-26T01:16:57.806418Z", "iopub.status.idle": "2026-05-26T01:16:57.812156Z", "shell.execute_reply": "2026-05-26T01:16:57.810680Z" }, "papermill": { "duration": 0.010609, "end_time": "2026-05-26T01:16:57.813488+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.802879+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "gmsh.initialize()\n", "gmsh.option.setNumber(\"General.Verbosity\", 5)\n", "gmsh.model.add(\"coax_to_waveguide\")\n", "kernel = gmsh.model.occ" ] }, { "cell_type": "markdown", "id": "efe871f2", "metadata": { "papermill": { "duration": 0.002334, "end_time": "2026-05-26T01:16:57.818723+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.816389+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Design Parameter Calculation\n", "We calculate the operating wavelength (λ) and derive the critical dimensions for the coaxial probe and backshort position. By basing these values on the 10 GHz design frequency, we ensure the geometry is physically optimized for efficient power transfer within the waveguide structure." ] }, { "cell_type": "code", "execution_count": 4, "id": "c319f238", "metadata": { "execution": { "iopub.execute_input": "2026-05-26T01:16:57.824716Z", "iopub.status.busy": "2026-05-26T01:16:57.824504Z", "iopub.status.idle": "2026-05-26T01:16:57.830087Z", "shell.execute_reply": "2026-05-26T01:16:57.828757Z" }, "papermill": { "duration": 0.010272, "end_time": "2026-05-26T01:16:57.831473+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.821201+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Wavelength: 30.00 mm\n", "Probe length: 5.89 mm\n", "Backshort Z position: 6.00 mm\n" ] } ], "source": [ "c = 3e8 \n", "lamda = (c / (freq_ghz * 1e9)) * 1e3 \n", "\n", "inner_radius = inner_diameter_mm / 2\n", "outer_radius = outer_diameter_mm / 2\n", "\n", "# y_top is the y-coordinate of the center of the coax probe, \n", "# which is typically placed at the center of the waveguide height\n", "y_top = wg_height / 2\n", "coax_y_max = y_top + length_mm\n", "\n", "# backshort_z is the distance from the probe tip to the backshort plane, \n", "# which is typically around λ/5 for good impedance matching\n", "backshort_z = lamda / 5\n", "\n", "print(f\"Wavelength: {lamda:.2f} mm\")\n", "print(f\"Probe length: {probe_length_mm:.2f} mm\")\n", "print(f\"Backshort Z position: {backshort_z:.2f} mm\")" ] }, { "cell_type": "markdown", "id": "f68f3975", "metadata": { "papermill": { "duration": 0.002471, "end_time": "2026-05-26T01:16:57.836651+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.834180+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Geometry Construction and Boolean Operations\n", "In this step, we construct the CAD model by defining the waveguide box and the coaxial feed components. We use Boolean cut operations to integrate the probe into the waveguide and define the dielectric region. Finally, we perform a global fragment operation to ensure all geometric volumes are properly connected, forming a unified topology ready for discretization." ] }, { "cell_type": "code", "execution_count": 5, "id": "6e4a92fd", "metadata": { "execution": { "iopub.execute_input": "2026-05-26T01:16:57.843150Z", "iopub.status.busy": "2026-05-26T01:16:57.842878Z", "iopub.status.idle": "2026-05-26T01:16:57.865248Z", "shell.execute_reply": "2026-05-26T01:16:57.863368Z" }, "papermill": { "duration": 0.026977, "end_time": "2026-05-26T01:16:57.866108+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.839131+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " \r" ] } ], "source": [ "# Waveguide box\n", "waveguide = kernel.addBox(\n", " -wg_width/2, -wg_height/2, 0,\n", " wg_width, wg_height, wg_length\n", ")\n", "\n", "# Outer coax cylinder\n", "outer_cyl = kernel.addCylinder(0, y_top, backshort_z, \n", " 0, length_mm, 0, outer_radius)\n", "\n", "# Inner conductor\n", "inner_cyl = kernel.addCylinder(0, coax_y_max, backshort_z, \n", " 0, -(length_mm + probe_length_mm), 0, inner_radius)\n", "\n", "kernel.synchronize()\n", "\n", "coax_dielectric, _ = kernel.cut([(3, outer_cyl)], [(3, inner_cyl)],\n", " removeObject=True, removeTool=False)\n", "\n", "waveguide_cut, _ = kernel.cut([(3, waveguide)], [(3, inner_cyl)],\n", " removeObject=True, removeTool= True)\n", "\n", "kernel.synchronize()\n", "\n", "all_volumes = gmsh.model.getEntities(3)\n", "kernel.fragment(all_volumes, [])\n", "kernel.synchronize()" ] }, { "cell_type": "markdown", "id": "8e4984ff", "metadata": { "papermill": { "duration": 0.003503, "end_time": "2026-05-26T01:16:57.873730+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.870227+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Geometric Entity Classification\n", "Here, we categorize the fragmented CAD entities into functional groups based on their spatial coordinates. We define logical filters to isolate the waveguide walls, coaxial conductors, waveports, and internal volumes. This classification step is essential for mapping the geometry to the specific physical boundary conditions required by the Palace solver" ] }, { "cell_type": "code", "execution_count": 6, "id": "eaf9f4d1", "metadata": { "execution": { "iopub.execute_input": "2026-05-26T01:16:57.882173Z", "iopub.status.busy": "2026-05-26T01:16:57.881905Z", "iopub.status.idle": "2026-05-26T01:16:57.893537Z", "shell.execute_reply": "2026-05-26T01:16:57.891904Z" }, "papermill": { "duration": 0.017313, "end_time": "2026-05-26T01:16:57.894543+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.877230+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "all_2d_entities = gmsh.model.getEntities(2)\n", "all_3d_entities = gmsh.model.getEntities(3)\n", "\n", "def is_interface(x):\n", " return (math.isclose(ymin(x), y_top, abs_tol=1e-4) and\n", " math.isclose(ymax(x), y_top, abs_tol=1e-4) and\n", " math.isclose(xmax(x), outer_radius, abs_tol=1e-4))\n", "\n", "def is_coax_port(x):\n", " return (math.isclose(ymin(x), coax_y_max, abs_tol=1e-4) and\n", " math.isclose(ymax(x), coax_y_max, abs_tol=1e-4) and\n", " math.isclose(xmax(x), outer_radius, abs_tol=1e-4))\n", "\n", "def is_inner_conductor(x):\n", " return (math.isclose(xmax(x), inner_radius, abs_tol=1e-4) and \n", " not is_interface(x))\n", "\n", "def is_outer_conductor(x):\n", " return (math.isclose(xmax(x), outer_radius, abs_tol=1e-4) and\n", " ymin(x) >= y_top - 1e-4 and\n", " not is_coax_port(x) and\n", " not is_interface(x))\n", "\n", "def is_waveport(x):\n", " return( math.isclose(zmax(x), wg_length, abs_tol=1e-4) and\n", " math.isclose(zmin(x), wg_length, abs_tol=1e-4))\n", "\n", "def is_waveguide_wall(x):\n", " return (not is_coax_port(x) and\n", " not is_inner_conductor(x) and\n", " not is_outer_conductor(x) and\n", " not is_waveport(x) and \n", " not is_interface(x)) \n", "\n", "def is_coax_volume(x):\n", " return ymin(x) >= y_top - 1e-4\n", "\n", "def is_waveguide_volume(x):\n", " return ymax(x) <= y_top + 1e-4 \n", "\n", "coax_port_surfs = [x for x in all_2d_entities if is_coax_port(x)]\n", "inner_cond_surfs = [x for x in all_2d_entities if is_inner_conductor(x)]\n", "outer_cond_surfs = [x for x in all_2d_entities if is_outer_conductor(x)]\n", "waveguide_wall_surfs = [x for x in all_2d_entities if is_waveguide_wall(x)]\n", "waveport_surfs = [x for x in all_2d_entities if is_waveport(x)] \n", "coax_vols = [x for x in all_3d_entities if is_coax_volume(x)]\n", "waveguide_vols = [x for x in all_3d_entities if is_waveguide_volume(x)]\n" ] }, { "cell_type": "markdown", "id": "57e05443", "metadata": { "papermill": { "duration": 0.003082, "end_time": "2026-05-26T01:16:57.900939+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.897857+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Physical Group Assignment\n", "In this block, we map the classified geometric entities to Physical Groups. Assigning these unique identifiers allows the Palace solver to distinguish between different materials and boundary conditions, such as the waveguide walls (PEC), the coaxial probe, and the internal air and dielectric volumes. Finally, we store these identifiers in a pg_map dictionary for streamlined reference during the simulation configuration." ] }, { "cell_type": "code", "execution_count": 7, "id": "27908878", "metadata": { "execution": { "iopub.execute_input": "2026-05-26T01:16:57.908263Z", "iopub.status.busy": "2026-05-26T01:16:57.907981Z", "iopub.status.idle": "2026-05-26T01:16:57.914741Z", "shell.execute_reply": "2026-05-26T01:16:57.913525Z" }, "papermill": { "duration": 0.011681, "end_time": "2026-05-26T01:16:57.915462+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.903781+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "pg_coax_port = gmsh.model.addPhysicalGroup(2, [x[1] for x in coax_port_surfs], -1, \"coax_port\")\n", "pg_probe = gmsh.model.addPhysicalGroup(2, [x[1] for x in inner_cond_surfs], -1, \"inner_conductor\")\n", "pg_outer_cyl = gmsh.model.addPhysicalGroup(2, [x[1] for x in outer_cond_surfs], -1, \"outer_conductor\")\n", "pg_waveguide = gmsh.model.addPhysicalGroup(2, [x[1] for x in waveguide_wall_surfs], -1, \"waveguide_walls\")\n", "pg_waveport = gmsh.model.addPhysicalGroup(2, [x[1] for x in waveport_surfs], -1, \"waveport\")\n", "pg_dieletric = gmsh.model.addPhysicalGroup(3, [x[1] for x in coax_vols], -1, \"coax_volume\")\n", "pg_air = gmsh.model.addPhysicalGroup(3, [x[1] for x in waveguide_vols], -1, \"waveguide_volume\")\n", "\n", "pg_map = {\n", " \"coax_port\": pg_coax_port,\n", " \"waveport\": pg_waveport,\n", " \"waveguide_surface\": pg_waveguide,\n", " \"waveguide_volume\": pg_air,\n", " \"probe\": pg_probe,\n", " \"outer_cyl\": pg_outer_cyl,\n", " \"dielectric\": pg_dieletric\n", " }" ] }, { "cell_type": "markdown", "id": "11b53216", "metadata": { "papermill": { "duration": 0.003553, "end_time": "2026-05-26T01:16:57.921739+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.918186+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Mesh Generation, Refinement, and Export\n", "We conclude the workflow by applying a graded mesh refinement strategy, concentrating element density near the coaxial feed and waveport to accurately resolve the high-frequency electromagnetic field gradients. " ] }, { "cell_type": "code", "execution_count": 8, "id": "2a5491ec", "metadata": { "execution": { "iopub.execute_input": "2026-05-26T01:16:57.929001Z", "iopub.status.busy": "2026-05-26T01:16:57.928773Z", "iopub.status.idle": "2026-05-26T01:16:59.680875Z", "shell.execute_reply": "2026-05-26T01:16:59.679775Z" }, "papermill": { "duration": 1.757407, "end_time": "2026-05-26T01:16:59.681957+00:00", "exception": false, "start_time": "2026-05-26T01:16:57.924550+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "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 : [ 20%] Meshing curve 4 (Line)\n", "Info : [ 30%] Meshing curve 5 (Line)\n", "Info : [ 30%] Meshing curve 6 (Line)\n", "Info : [ 40%] Meshing curve 7 (Line)\n", "Info : [ 40%] Meshing curve 8 (Line)\n", "Info : [ 50%] Meshing curve 9 (Line)\n", "Info : [ 50%] Meshing curve 10 (Line)\n", "Info : [ 60%] Meshing curve 11 (Line)\n", "Info : [ 60%] Meshing curve 12 (Circle)\n", "Info : [ 70%] Meshing curve 13 (Circle)\n", "Info : [ 70%] Meshing curve 14 (Line)\n", "Info : [ 80%] Meshing curve 15 (Line)\n", "Info : [ 80%] Meshing curve 16 (Circle)\n", "Info : [ 90%] Meshing curve 17 (Circle)\n", "Info : [ 90%] Meshing curve 18 (Line)\n", "Info : [100%] Meshing curve 19 (Circle)\n", "Info : [100%] Meshing curve 20 (Line)\n", "Info : Done meshing 1D (Wall 0.0688756s, CPU 0.070071s)\n", "Info : Meshing 2D...\n", "Info : [ 0%] Meshing surface 1 (Plane, MeshAdapt)\n", "Info : [ 10%] Meshing surface 2 (Plane, MeshAdapt)\n", "Info : [ 20%] Meshing surface 3 (Plane, MeshAdapt)\n", "Info : [ 30%] Meshing surface 4 (Plane, MeshAdapt)\n", "Info : [ 40%] Meshing surface 5 (Plane, MeshAdapt)\n", "Info : [ 50%] Meshing surface 6 (Plane, MeshAdapt)\n", "Info : [ 60%] Meshing surface 7 (Plane, MeshAdapt)\n", "Info : [ 60%] Meshing surface 8 (Cylinder, MeshAdapt)\n", "Info : [ 70%] Meshing surface 9 (Plane, MeshAdapt)\n", "Info : [ 80%] Meshing surface 10 (Cylinder, MeshAdapt)\n", "Info : [ 90%] Meshing surface 11 (Plane, MeshAdapt)\n", "Info : [100%] Meshing surface 12 (Cylinder, MeshAdapt)\n", "Info : Done meshing 2D (Wall 0.128015s, CPU 0.118216s)\n", "Info : Meshing 3D...\n", "Info : 3D Meshing 2 volumes with 1 connected component\n", "Info : Tetrahedrizing 2478 nodes...\n", "Info : Done tetrahedrizing 2486 nodes (Wall 0.019306s, CPU 0.018991s)\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.0447786s, CPU 0.040989s)\n", "Info : Found volume 1\n", "Info : Found volume 2\n", "Info : It. 0 - 0 nodes created - worst tet radius 5.10984 (nodes removed 0 0)\n", "Info : It. 500 - 500 nodes created - worst tet radius 1.38331 (nodes removed 0 0)\n", "Info : It. 1000 - 1000 nodes created - worst tet radius 1.14555 (nodes removed 0 0)\n", "Info : It. 1500 - 1500 nodes created - worst tet radius 1.01555 (nodes removed 0 0)\n", "Info : 3D refinement terminated (4074 nodes total):\n", "Info : - 1 Delaunay cavities modified for star shapeness\n", "Info : - 0 nodes could not be inserted\n", "Info : - 17595 tetrahedra created in 0.0557985 sec. (315331 tets/s)\n", "Info : 0 node relocations\n", "Info : Done meshing 3D (Wall 0.135981s, CPU 0.131193s)\n", "Info : Optimizing mesh...\n", "Info : Optimizing volume 1\n", "Info : Optimization starts (volume = 9283.88) with worst = 0.0112082 / average = 0.7543:\n", "Info : 0.00 < quality < 0.10 : 46 elements\n", "Info : 0.10 < quality < 0.20 : 131 elements\n", "Info : 0.20 < quality < 0.30 : 227 elements\n", "Info : 0.30 < quality < 0.40 : 324 elements\n", "Info : 0.40 < quality < 0.50 : 526 elements\n", "Info : 0.50 < quality < 0.60 : 1048 elements\n", "Info : 0.60 < quality < 0.70 : 2411 elements\n", "Info : 0.70 < quality < 0.80 : 4363 elements\n", "Info : 0.80 < quality < 0.90 : 5466 elements\n", "Info : 0.90 < quality < 1.00 : 2448 elements\n", "Info : 398 edge swaps, 2 node relocations (volume = 9283.88): worst = 0.230379 / average = 0.768879 (Wall 0.00519735s, CPU 0.005208s)\n", "Info : 399 edge swaps, 2 node relocations (volume = 9283.88): worst = 0.3 / average = 0.768906 (Wall 0.00605874s, CPU 0.006103s)\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 : 310 elements\n", "Info : 0.40 < quality < 0.50 : 510 elements\n", "Info : 0.50 < quality < 0.60 : 1039 elements\n", "Info : 0.60 < quality < 0.70 : 2404 elements\n", "Info : 0.70 < quality < 0.80 : 4404 elements\n", "Info : 0.80 < quality < 0.90 : 5508 elements\n", "Info : 0.90 < quality < 1.00 : 2448 elements\n", "Info : Optimizing volume 2\n", "Info : Optimization starts (volume = 44.3679) with worst = 0.0689716 / average = 0.695575:\n", "Info : 0.00 < quality < 0.10 : 1 elements\n", "Info : 0.10 < quality < 0.20 : 5 elements\n", "Info : 0.20 < quality < 0.30 : 10 elements\n", "Info : 0.30 < quality < 0.40 : 5 elements\n", "Info : 0.40 < quality < 0.50 : 28 elements\n", "Info : 0.50 < quality < 0.60 : 57 elements\n", "Info : 0.60 < quality < 0.70 : 157 elements\n", "Info : 0.70 < quality < 0.80 : 228 elements\n", "Info : 0.80 < quality < 0.90 : 103 elements\n", "Info : 0.90 < quality < 1.00 : 11 elements\n", "Info : 16 edge swaps, 0 node relocations (volume = 44.3679): worst = 0.277905 / average = 0.707631 (Wall 0.000170567s, CPU 0.000196s)\n", "Info : 18 edge swaps, 0 node relocations (volume = 44.3679): worst = 0.322615 / average = 0.709237 (Wall 0.000224197s, CPU 0.000261s)\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 : 4 elements\n", "Info : 0.40 < quality < 0.50 : 24 elements\n", "Info : 0.50 < quality < 0.60 : 60 elements\n", "Info : 0.60 < quality < 0.70 : 160 elements\n", "Info : 0.70 < quality < 0.80 : 232 elements\n", "Info : 0.80 < quality < 0.90 : 100 elements\n", "Info : 0.90 < quality < 1.00 : 11 elements\n", "Info : Done optimizing mesh (Wall 0.0186066s, CPU 0.018026s)\n", "Info : 4074 nodes 22560 elements\n", "Info : Optimizing mesh (Netgen)...\n", "Info : Optimizing volume 1\n", "Info : CalcLocalH: 3894 Points 16623 Elements 4592 Surface Elements \n", "Info : Remove Illegal Elements \n", "Info : 849 illegal tets \n", "Info : SplitImprove \n", "Info : badmax = 19.2097 \n", "Info : 132 splits performed \n", "Info : SwapImprove \n", "Info : 162 swaps performed \n", "Info : SwapImprove2 \n", "Info : 6 swaps performed \n", "Info : 533 illegal tets \n", "Info : SplitImprove \n", "Info : badmax = 1512.76 \n", "Info : 129 splits performed \n", "Info : SwapImprove \n", "Info : 64 swaps performed \n", "Info : SwapImprove2 \n", "Info : 8 swaps performed \n", "Info : 184 illegal tets \n", "Info : SplitImprove \n", "Info : badmax = 643.824 \n", "Info : 53 splits performed \n", "Info : SwapImprove \n", "Info : 6 swaps performed \n", "Info : SwapImprove2 \n", "Info : 3 swaps performed \n", "Info : 47 illegal tets \n", "Info : SplitImprove \n", "Info : badmax = 4612.07 \n", "Info : 15 splits performed \n", "Info : SwapImprove \n", "Info : 1 swaps performed \n", "Info : SwapImprove2 \n", "Info : 0 swaps performed \n", "Info : 7 illegal tets \n", "Info : SplitImprove \n", "Info : badmax = 643.824 \n", "Info : 1 splits performed \n", "Info : SwapImprove \n", "Info : 0 swaps performed \n", "Info : SwapImprove2 \n", "Info : 0 swaps performed \n", "Info : 5 illegal tets \n", "Info : SplitImprove \n", "Info : badmax = 643.824 \n", "Info : 1 splits performed \n", "Info : SwapImprove \n", "Info : 0 swaps performed \n", "Info : SwapImprove2 \n", "Info : 0 swaps performed \n", "Info : 2 illegal tets \n", "Info : SplitImprove \n", "Info : badmax = 643.824 \n", "Info : 1 splits performed \n", "Info : SwapImprove \n", "Info : 0 swaps performed \n", "Info : SwapImprove2 \n", "Info : 0 swaps performed \n", "Info : 0 illegal tets \n", "Info : Volume Optimization \n", "Info : CombineImprove \n", "Info : 187 elements combined \n", "Info : ImproveMesh \n", "Info : Total badness = 25994.5 \n", "Info : Total badness = 24658.1 \n", "Info : SplitImprove \n", "Info : badmax = 26.2601 \n", "Info : 1 splits performed \n", "Info : ImproveMesh \n", "Info : Total badness = 24663.8 \n", "Info : Total badness = 24480.3 \n", "Info : SwapImprove \n", "Info : 1068 swaps performed \n", "Info : SwapImprove2 \n", "Info : 0 swaps performed \n", "Info : ImproveMesh \n", "Info : Total badness = 22625.6 \n", "Info : Total badness = 22076.3 \n", "Info : CombineImprove \n", "Info : 18 elements combined \n", "Info : ImproveMesh \n", "Info : Total badness = 21913.7 \n", "Info : Total badness = 21864.4 \n", "Info : SplitImprove \n", "Info : badmax = 16.4601 \n", "Info : 0 splits performed \n", "Info : ImproveMesh \n", "Info : Total badness = 21864.4 \n", "Info : Total badness = 21858.7 \n", "Info : SwapImprove \n", "Info : 239 swaps performed \n", "Info : SwapImprove2 \n", "Info : 0 swaps performed \n", "Info : ImproveMesh \n", "Info : Total badness = 21657.3 \n", "Info : Total badness = 21509.1 \n", "Info : CombineImprove \n", "Info : 13 elements combined \n", "Info : ImproveMesh \n", "Info : Total badness = 21376.5 \n", "Info : Total badness = 21357.7 \n", "Info : SplitImprove \n", "Info : badmax = 11.0073 \n", "Info : 0 splits performed \n", "Info : ImproveMesh \n", "Info : Total badness = 21357.7 \n", "Info : Total badness = 21356.2 \n", "Info : SwapImprove \n", "Info : 107 swaps performed \n", "Info : SwapImprove2 \n", "Info : 0 swaps performed \n", "Info : ImproveMesh \n", "Info : Total badness = 21304 \n", "Info : Total badness = 21240.1 \n", "Info : Optimizing volume 2\n", "Info : CalcLocalH: 218 Points 591 Elements 436 Surface Elements \n", "Info : Remove Illegal Elements \n", "Info : 170 illegal tets \n", "Info : SplitImprove \n", "Info : badmax = 15.5651 \n", "Info : 18 splits performed \n", "Info : SwapImprove \n", "Info : 18 swaps performed \n", "Info : SwapImprove2 \n", "Info : 0 swaps performed \n", "Info : 128 illegal tets \n", "Info : SplitImprove \n", "Info : badmax = 15.5651 \n", "Info : 16 splits performed \n", "Info : SwapImprove \n", "Info : 6 swaps performed \n", "Info : SwapImprove2 \n", "Info : 0 swaps performed \n", "Info : 90 illegal tets \n", "Info : SplitImprove \n", "Info : badmax = 18.1167 \n", "Info : 12 splits performed \n", "Info : SwapImprove \n", "Info : 6 swaps performed \n", "Info : SwapImprove2 \n", "Info : 2 swaps performed \n", "Info : 62 illegal tets \n", "Info : SplitImprove \n", "Info : badmax = 196.553 \n", "Info : 11 splits performed \n", "Info : SwapImprove \n", "Info : 6 swaps performed \n", "Info : SwapImprove2 \n", "Info : 1 swaps performed \n", "Info : 33 illegal tets \n", "Info : SplitImprove \n", "Info : badmax = 196.553 \n", "Info : 8 splits performed \n", "Info : SwapImprove \n", "Info : 4 swaps performed \n", "Info : SwapImprove2 \n", "Info : 0 swaps performed \n", "Info : 7 illegal tets \n", "Info : SplitImprove \n", "Info : badmax = 196.553 \n", "Info : 2 splits performed \n", "Info : SwapImprove \n", "Info : 0 swaps performed \n", "Info : SwapImprove2 \n", "Info : 1 swaps performed \n", "Info : 0 illegal tets \n", "Info : Volume Optimization \n", "Info : CombineImprove \n", "Info : 23 elements combined \n", "Info : ImproveMesh \n", "Info : Total badness = 1527.24 \n", "Info : Total badness = 1486.36 \n", "Info : SplitImprove \n", "Info : badmax = 19.2346 \n", "Info : 0 splits performed \n", "Info : ImproveMesh \n", "Info : Total badness = 1486.36 \n", "Info : Total badness = 1485.72 \n", "Info : SwapImprove \n", "Info : 36 swaps performed \n", "Info : SwapImprove2 \n", "Info : 0 swaps performed \n", "Info : ImproveMesh \n", "Info : Total badness = 1438.64 \n", "Info : Total badness = 1419.21 \n", "Info : CombineImprove \n", "Info : 2 elements combined \n", "Info : ImproveMesh \n", "Info : Total badness = 1400.97 \n", "Info : Total badness = 1399.34 \n", "Info : SplitImprove \n", "Info : badmax = 19.8755 \n", "Info : 1 splits performed \n", "Info : ImproveMesh \n", "Info : Total badness = 1403.89 \n", "Info : Total badness = 1401.13 \n", "Info : SwapImprove \n", "Info : 17 swaps performed \n", "Info : SwapImprove2 \n", "Info : 0 swaps performed \n", "Info : ImproveMesh \n", "Info : Total badness = 1381.54 \n", "Info : Total badness = 1367.13 \n", "Info : CombineImprove \n", "Info : 4 elements combined \n", "Info : ImproveMesh \n", "Info : Total badness = 1323.25 \n", "Info : Total badness = 1320.26 \n", "Info : SplitImprove \n", "Info : badmax = 14.5745 \n", "Info : 0 splits performed \n", "Info : ImproveMesh \n", "Info : Total badness = 1320.26 \n", "Info : Total badness = 1320.18 \n", "Info : SwapImprove \n", "Info : 7 swaps performed \n", "Info : SwapImprove2 \n", "Info : 0 swaps performed \n", "Info : ImproveMesh \n", "Info : Total badness = 1311.37 \n", "Info : Total badness = 1308.24 \n", "Info : Done optimizing mesh (Wall 0.739781s, CPU 0.740042s)\n", "Info : Writing '/home/martin/Desktop/PalaceToolkit/docs/examples/coax_to_waveguide.msh'...\n", "Info : Done writing '/home/martin/Desktop/PalaceToolkit/docs/examples/coax_to_waveguide.msh'\n" ] }, { "data": { "text/html": [ "
Coax-to-waveguide mesh generation
  ppw_near=50  ppw_far=20\n",
       "  SizeMax=1.5000  transition=3.7500\n",
       "  global: 12 curves, SizeMin=0.6000
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def _generate_coax_to_waveguide_mesh():\n", " refine_near_surfaces([(2, extract_tag(x)) for x in inner_cond_surfs + outer_cond_surfs + waveport_surfs + coax_port_surfs], \n", " wavelength= lamda,\n", " ppw_near = 50,\n", " ppw_far = 20,\n", " transition_distance= lamda / 8,\n", " )\n", "\n", " gmsh.model.mesh.generate(3)\n", " gmsh.model.mesh.setOrder(order)\n", " gmsh.model.mesh.optimize(\"Netgen\")\n", "\n", " gmsh.option.setNumber(\"Mesh.MshFileVersion\", 2.2)\n", " gmsh.option.setNumber(\"Mesh.Binary\", 0)\n", "\n", " script_dir = os.getcwd()\n", " output_path = os.path.join(script_dir, filename)\n", " gmsh.write(output_path)\n", "\n", "run_with_scrollable_output(_generate_coax_to_waveguide_mesh, title=\"Coax-to-waveguide mesh generation\", max_lines=10)\n", "\n", "if gui:\n", " gmsh.fltk.run()\n", "\n", "gmsh.finalize()" ] }, { "cell_type": "code", "execution_count": 9, "id": "3b16145d", "metadata": { "execution": { "iopub.execute_input": "2026-05-26T01:16:59.689446Z", "iopub.status.busy": "2026-05-26T01:16:59.689176Z", "iopub.status.idle": "2026-05-26T01:17:00.871169Z", "shell.execute_reply": "2026-05-26T01:17:00.869682Z" }, "papermill": { "duration": 1.187009, "end_time": "2026-05-26T01:17:00.872163+00:00", "exception": false, "start_time": "2026-05-26T01:16:59.685154+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Loading mesh file: coax_to_waveguide.msh\n", "Groups to render transparent: air_sphere__None\n", "\n", "Mesh loaded successfully with 2 cell blocks\n", "Found 4928 triangles total\n", "Physical group tags in mesh: {1: 'coax_port', 2: 'inner_conductor', 3: 'outer_conductor', 4: 'waveguide_walls', 5: 'waveport'}\n" ] }, { "data": { "text/html": [ "
" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "view_mesh(filename, transparent_groups= \"air_sphere__None\")" ] }, { "cell_type": "markdown", "id": "dc4fc716", "metadata": { "papermill": { "duration": 0.00566, "end_time": "2026-05-26T01:17:00.884219+00:00", "exception": false, "start_time": "2026-05-26T01:17:00.878559+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Generating the Palace Configuration File\n", "Finally, we assemble the simulation parameters into a JSON configuration file. This file serves as the definitive input for Palace." ] }, { "cell_type": "code", "execution_count": 10, "id": "27e21aa2", "metadata": { "execution": { "iopub.execute_input": "2026-05-26T01:17:00.898318Z", "iopub.status.busy": "2026-05-26T01:17:00.897977Z", "iopub.status.idle": "2026-05-26T01:17:00.905547Z", "shell.execute_reply": "2026-05-26T01:17:00.904277Z" }, "papermill": { "duration": 0.015939, "end_time": "2026-05-26T01:17:00.906534+00:00", "exception": false, "start_time": "2026-05-26T01:17:00.890595+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Palace config successfully generated: coax_to_waveguide.json\n" ] } ], "source": [ "palace_config = {\n", " \"Problem\": {\n", " \"Type\": \"Driven\",\n", " \"Verbose\": 2,\n", " \"Output\": \"/work/postpro/coax2waveguide\"\n", " },\n", " \"Model\": {\n", " \"Mesh\": f\"/work/coax_to_waveguide.msh\", \n", " \"L0\": 1e-3,\n", " \"Refinement\": {}\n", " },\n", " \"Domains\": {\n", " \"Materials\": [\n", " {\n", " \"Attributes\": [pg_map[\"waveguide_volume\"]],\n", " \"Permittivity\": 1.0,\n", " \"Permeability\": 1.0\n", " },\n", " {\n", " \"Attributes\": [pg_map[\"dielectric\"]],\n", " \"Permittivity\": 2.2, \n", " \"Permeability\": 1.0\n", " }\n", " ]\n", " },\n", " \"Boundaries\": {\n", " \"PEC\": {\n", " \"Attributes\": [pg_map[\"waveguide_surface\"]] + [pg_map[\"outer_cyl\"]] + [pg_map[\"probe\"]]\n", " },\n", " \"WavePort\": [\n", " {\n", " \"Index\": 2, \n", " \"Attributes\": [pg_map[\"waveport\"]],\n", " \"Mode\": 1,\n", " \"Offset\": 0.0\n", " },\n", " {\n", " \"Index\": 1, \n", " \"Attributes\": [pg_map[\"coax_port\"]],\n", " \"Mode\": 1,\n", " \"Offset\": 0.0,\n", " \"Excitation\": True\n", " }\n", " ] \n", " },\n", " \"Solver\": {\n", " \"Order\": 2,\n", " \"Device\": \"CPU\",\n", " \"Driven\": {\n", "\n", " \"MinFreq\": 6.0,\n", " \"MaxFreq\": 12.0,\n", " \"FreqStep\": 0.1,\n", " \"SaveStep\": 2,\n", " \"AdaptiveTol\": 0.001\n", " },\n", " \"Linear\": {\n", " \"Type\": \"Default\",\n", " \"KSPType\": \"GMRES\",\n", " \"Tol\": 1e-08,\n", " \"MaxIts\": 200,\n", " \"ComplexCoarseSolve\": True\n", " }\n", " }\n", "}\n", "\n", "with open(\"coax_to_waveguide.json\", 'w') as json_file:\n", " json.dump(palace_config, json_file, indent=4)\n", " \n", "print(f\"Palace config successfully generated: coax_to_waveguide.json\")" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "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" }, "papermill": { "default_parameters": {}, "duration": 5.600334, "end_time": "2026-05-26T01:17:01.431753+00:00", "environment_variables": {}, "exception": null, "input_path": "docs/examples/coax_to_waveguide.ipynb", "output_path": "docs/examples/coax_to_waveguide.ipynb", "parameters": {}, "start_time": "2026-05-26T01:16:55.831419+00:00", "version": "2.7.0" }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": { "0b449f6179b147e595b2d983dccd0cef": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLModel", "state": { "_dom_classes": [], "_model_module": "@jupyter-widgets/controls", "_model_module_version": "2.0.0", "_model_name": "HTMLModel", "_view_count": null, "_view_module": "@jupyter-widgets/controls", "_view_module_version": "2.0.0", "_view_name": "HTMLView", "description": "", "description_allow_html": false, "layout": "IPY_MODEL_cba903637cd14c2fbc85255b9e32a87b", "placeholder": "​", "style": "IPY_MODEL_9f626e580e504bd090671d840e923e71", "tabbable": null, "tooltip": null, "value": "" } }, "9f626e580e504bd090671d840e923e71": { "model_module": "@jupyter-widgets/controls", "model_module_version": "2.0.0", "model_name": "HTMLStyleModel", "state": { "_model_module": "@jupyter-widgets/controls", "_model_module_version": "2.0.0", "_model_name": "HTMLStyleModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "2.0.0", "_view_name": "StyleView", "background": null, "description_width": "", "font_size": null, "text_color": null } }, "cba903637cd14c2fbc85255b9e32a87b": { "model_module": "@jupyter-widgets/base", "model_module_version": "2.0.0", "model_name": "LayoutModel", "state": { "_model_module": "@jupyter-widgets/base", "_model_module_version": "2.0.0", "_model_name": "LayoutModel", "_view_count": null, "_view_module": "@jupyter-widgets/base", "_view_module_version": "2.0.0", "_view_name": "LayoutView", "align_content": null, "align_items": null, "align_self": null, "border_bottom": null, "border_left": null, "border_right": null, "border_top": null, "bottom": null, "display": null, "flex": null, "flex_flow": null, "grid_area": null, "grid_auto_columns": null, "grid_auto_flow": null, "grid_auto_rows": null, "grid_column": null, "grid_gap": null, "grid_row": null, "grid_template_areas": null, "grid_template_columns": null, "grid_template_rows": null, "height": null, "justify_content": null, "justify_items": null, "left": null, "margin": null, "max_height": null, "max_width": null, "min_height": null, "min_width": null, "object_fit": null, "object_position": null, "order": null, "overflow": null, "padding": null, "right": null, "top": null, "visibility": null, "width": null } } }, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 5 }