{ "cells": [ { "cell_type": "markdown", "id": "5ed63800", "metadata": { "papermill": { "duration": 0.002025, "end_time": "2026-05-27T20:00:55.495376+00:00", "exception": false, "start_time": "2026-05-27T20:00:55.493351+00:00", "status": "completed" }, "tags": [] }, "source": [ "### L shaped antenna simulation.\n", "\n", "In this notebook we will generate the mesh of an L shaped antenna and generate a json for a transient\n", "simulation." ] }, { "cell_type": "code", "execution_count": 15, "id": "9437354e", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:00:55.502114Z", "iopub.status.busy": "2026-05-27T20:00:55.501907Z", "iopub.status.idle": "2026-05-27T20:00:55.864001Z", "shell.execute_reply": "2026-05-27T20:00:55.863420Z" }, "papermill": { "duration": 0.365343, "end_time": "2026-05-27T20:00:55.864781+00:00", "exception": false, "start_time": "2026-05-27T20:00:55.499438+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "import gmsh\n", "import os\n", "import json\n", "\n", "from palacetoolkit.viz import view_mesh\n", "from palacetoolkit.mesh import (\n", " Entity, \n", " run_meshing_pipeline, \n", " generate_3d_mesh, \n", " refine_near_surfaces\n", ")" ] }, { "cell_type": "markdown", "id": "1d956d7d", "metadata": { "papermill": { "duration": 0.003929, "end_time": "2026-05-27T20:00:55.870459+00:00", "exception": false, "start_time": "2026-05-27T20:00:55.866530+00:00", "status": "completed" }, "tags": [] }, "source": [ "\n", "### Parameters:\n", "- h : Patch height along z-axis, specified as a scalar in meters. \n", "- l1 : Ground plane length along x-axis, specified as a scalar in meters\n", "- w1 : Ground plane width along y-axis, specified as a scalar in meters\n", "- w3 : Strip line width along y-axis, specified as a scalar in meters.\n", "- air_height : Air box height along z-axis, specified as a scalar in meters. \n", "- air_margin : Air box margin along x and y axes, specified as a scalar in meters.\n", "- freq : Simulation frequency in GHz, specified as a scalar.\n", "- filename : Output mesh filename, specified as a string." ] }, { "cell_type": "code", "execution_count": 16, "id": "4049c4db", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:00:55.874959Z", "iopub.status.busy": "2026-05-27T20:00:55.874680Z", "iopub.status.idle": "2026-05-27T20:00:55.878448Z", "shell.execute_reply": "2026-05-27T20:00:55.877853Z" }, "papermill": { "duration": 0.006796, "end_time": "2026-05-27T20:00:55.878999+00:00", "exception": false, "start_time": "2026-05-27T20:00:55.872203+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "l1: float = 0.06\n", "w1: float = 0.06\n", "w3: float = 0.002\n", "h: float = 0.0013\n", "air_height: float = 0.025 \n", "air_margin: float = 0.025 \n", "freq: float = 3.3\n", "mesh_file: str = \"l_antenna.msh\"\n", "\n", "\n", "eps_r: float = 2.2\n", "loss_tan: float = 0.0009\n", "\n", "wavelength = 3e8 / (freq * 1e9)\n", "mesh_size = wavelength / 15" ] }, { "cell_type": "markdown", "id": "6d496609", "metadata": { "papermill": { "duration": 0.001629, "end_time": "2026-05-27T20:00:55.882261+00:00", "exception": false, "start_time": "2026-05-27T20:00:55.880632+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Initialize the model" ] }, { "cell_type": "code", "execution_count": 17, "id": "e6a08089", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:00:55.885728Z", "iopub.status.busy": "2026-05-27T20:00:55.885592Z", "iopub.status.idle": "2026-05-27T20:00:55.888774Z", "shell.execute_reply": "2026-05-27T20:00:55.888373Z" }, "papermill": { "duration": 0.005699, "end_time": "2026-05-27T20:00:55.889357+00:00", "exception": false, "start_time": "2026-05-27T20:00:55.883658+00:00", "status": "completed" }, "tags": [] }, "outputs": [], "source": [ "gmsh.initialize()\n", "gmsh.model.add(\"patch_antenna\")\n", "kernel = gmsh.model.occ" ] }, { "cell_type": "markdown", "id": "783686ab", "metadata": { "papermill": { "duration": 0.001329, "end_time": "2026-05-27T20:00:55.892238+00:00", "exception": false, "start_time": "2026-05-27T20:00:55.890909+00:00", "status": "completed" }, "tags": [] }, "source": [ "### Geometry Construction\n" ] }, { "cell_type": "code", "execution_count": 18, "id": "474cc986", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:00:55.896136Z", "iopub.status.busy": "2026-05-27T20:00:55.895972Z", "iopub.status.idle": "2026-05-27T20:00:55.905951Z", "shell.execute_reply": "2026-05-27T20:00:55.905516Z" }, "papermill": { "duration": 0.01254, "end_time": "2026-05-27T20:00:55.906506+00:00", "exception": false, "start_time": "2026-05-27T20:00:55.893966+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Info : Cannot bind existing OpenCASCADE surface 9 to second tag 10 \n", "Info : Could not preserve tag of 2D object 10 (->9)\n" ] } ], "source": [ "total_xmin = -l1/2 - air_margin\n", "total_xmax = l1/2 + air_margin\n", "total_ymin = -w1/2 - air_margin\n", "total_ymax = w1/2 + air_margin\n", "total_zmax = h + air_height\n", "\n", "\n", "# 1. Create volumes\n", "substrate = kernel.addBox(-l1/2, -w1/2, 0, l1, w1, h)\n", "airsphere_radius = max(abs(total_xmin), abs(total_xmax), abs(total_ymin), abs(total_ymax), total_zmax)\n", "air_sphere = kernel.addSphere(0.0, 0.0, 0.0, airsphere_radius)\n", "kernel.synchronize()\n", "\n", "# 2. Create 2D surfaces (ground, patch, ports)\n", "ground_plane = kernel.addRectangle(-l1/2, -w1/2, 0, l1, w1)\n", "\n", "strip_length_x = l1/2\n", "strip_length_y = w1/2 + w3/2\n", "\n", "feed_line_x = kernel.addRectangle(-l1/2, -w3/2, h, strip_length_x, w3)\n", "feed_line_y = kernel.addRectangle(0, -w3/2, h, w3, strip_length_y)\n", "\n", "top_conductor, top_map = kernel.fuse(\n", " [(2, feed_line_x)], [(2, feed_line_y)],\n", " removeObject=True, removeTool=True\n", ")\n", "kernel.synchronize()\n", "\n", "# Lumped ports - build directly in-plane, no rotation\n", "# Port 1: at x = -l1/2, vertical face\n", "p1 = kernel.addPoint(-l1/2, -w3/2, 0)\n", "p2 = kernel.addPoint(-l1/2, w3/2, 0)\n", "p3 = kernel.addPoint(-l1/2, w3/2, h)\n", "p4 = kernel.addPoint(-l1/2, -w3/2, h)\n", "\n", "lp1_a = kernel.addLine(p1, p2)\n", "lp1_b = kernel.addLine(p2, p3)\n", "lp1_c = kernel.addLine(p3, p4)\n", "lp1_d = kernel.addLine(p4, p1)\n", "loop1 = kernel.addCurveLoop([lp1_a, lp1_b, lp1_c, lp1_d])\n", "lumped_port_1 = kernel.addPlaneSurface([loop1])\n", "kernel.synchronize()\n", "\n", "# Port 2: at y = w1/2, vertical face\n", "p5 = kernel.addPoint(0, w1/2, 0)\n", "p6 = kernel.addPoint(w3, w1/2, 0)\n", "p7 = kernel.addPoint(w3, w1/2, h)\n", "p8 = kernel.addPoint(0, w1/2, h)\n", "\n", "lp2_a = kernel.addLine(p5, p6)\n", "lp2_b = kernel.addLine(p6, p7)\n", "lp2_c = kernel.addLine(p7, p8)\n", "lp2_d = kernel.addLine(p8, p5)\n", "loop2 = kernel.addCurveLoop([lp2_a, lp2_b, lp2_c, lp2_d])\n", "lumped_port_2 = kernel.addPlaneSurface([loop2])\n", "kernel.synchronize()\n", "\n", "# Define the entities which will be the physical groups.\n", "entities = [\n", " Entity(\"substrate\", dim=3, btype=\"dielectric\", mesh_order=1, tags=[substrate], loss_tan=loss_tan, eps_r=eps_r, mu_r=1.0),\n", " Entity(\"air_sphere\", dim=3, btype=\"dielectric\", mesh_order=2, tags=[air_sphere], loss_tan=0.0, eps_r=1.0, mu_r=1.0),\n", " Entity(\"top_conductor\", dim=2, btype=\"pec\", mesh_order=1, tags=[top_conductor[0][1]]),\n", " Entity(\"ground_plane\", dim=2, btype=\"pec\", mesh_order=1, tags=[ground_plane]),\n", " Entity(\"lumped_port_1\", dim=2, btype=\"lumped_port\", mesh_order=0, tags=[lumped_port_1], R=50.0, direction=\"+Z\", excitation=True),\n", " Entity(\"lumped_port_2\", dim=2, btype=\"lumped_port\", mesh_order=0, tags=[lumped_port_2], R=50.0, direction=\"+Z\", excitation=False),\n", "]\n" ] }, { "cell_type": "code", "execution_count": 19, "id": "ecf93353", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:00:55.910655Z", "iopub.status.busy": "2026-05-27T20:00:55.910462Z", "iopub.status.idle": "2026-05-27T20:00:57.281541Z", "shell.execute_reply": "2026-05-27T20:00:57.280876Z" }, "papermill": { "duration": 1.37416, "end_time": "2026-05-27T20:00:57.282385+00:00", "exception": false, "start_time": "2026-05-27T20:00:55.908225+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Physical group 'substrate' (dim=3): pg=1, tags=[1] \n", " Physical group 'air_sphere' (dim=3): pg=2, tags=[2]\n", " Physical group 'top_conductor' (dim=2): pg=3, tags=[9]\n", " Physical group 'ground_plane' (dim=2): pg=4, tags=[8]\n", " Physical group 'lumped_port_1' (dim=2): pg=5, tags=[10]\n", " Physical group 'lumped_port_2' (dim=2): pg=6, tags=[11]\n", " Physical group 'air_sphere__substrate' (dim=2): pg=7, tags=[12, 13, 14, 15, 16, 17, 18, 19]\n", " Physical group 'air_sphere__None' (dim=2): pg=8, tags=[20]\n", " ppw_near=100 ppw_far=15\n", " SizeMax=0.0061 transition=0.0227\n", " global: 6 curves, SizeMin=0.0009\n", " local (2, 11): 4 curves, SizeMin=0.0009\n", " local (2, 10): 4 curves, SizeMin=0.0009\n", " Merged 3 fields with Min → field 7\n" ] } ], "source": [ "pg_map = run_meshing_pipeline(entities)\n", "\n", "lumped_port_1 = entities[-1].dimtags[0]\n", "lumped_port_2 = entities[-2].dimtags[0]\n", "\n", "# Refine near the top conductor and also locally refine the ports.\n", "refine_near_surfaces(entities[2].dimtags, \n", " wavelength, \n", " ppw_near=100, \n", " ppw_far=15, \n", " set_as_background=True,\n", " local_refinements = {lumped_port_1: 100, lumped_port_2 : 100})\n", "\n", "mesh_sizes = {\n", " \"substrate\": wavelength / 12,\n", " \"air_sphere\": wavelength / 4,\n", " \"lumped_port_1\": wavelength / 18,\n", " \"lumped_port_2\": wavelength / 18,\n", " \"top_conductor\": wavelength /10\n", "}\n", "\n", "generate_3d_mesh(entities, mesh_sizes, mesh_file, optimize=True, verbose=False)\n", "gmsh.finalize()" ] }, { "cell_type": "code", "execution_count": 20, "id": "f2fc1ec1", "metadata": { "execution": { "iopub.execute_input": "2026-05-27T20:00:57.286581Z", "iopub.status.busy": "2026-05-27T20:00:57.286452Z", "iopub.status.idle": "2026-05-27T20:00:58.038052Z", "shell.execute_reply": "2026-05-27T20:00:58.037446Z" }, "papermill": { "duration": 0.765281, "end_time": "2026-05-27T20:00:58.049563+00:00", "exception": false, "start_time": "2026-05-27T20:00:57.284282+00:00", "status": "completed" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Loading mesh file: l_antenna.msh\n", "Groups to render transparent: air_sphere__None\n", "\n", "Mesh loaded successfully with 2 cell blocks\n", "Found 5922 triangles total\n", "Physical group tags in mesh: {3: 'top_conductor', 4: 'ground_plane', 5: 'lumped_port_1', 6: 'lumped_port_2', 7: 'air_sphere__substrate', 8: 'air_sphere__None'}\n" ] }, { "data": { "text/html": [ "
" ], "text/plain": [ "