Patch Antenna
Patch Antenna¶
We now apply a refined mesh for the patch antenna. Because the electromagnetic fields change rapidly near the metallic patch and the substrate edges, we increase the mesh density in these areas to ensure high simulation accuracy for resonance and radiation patterns.
import gmsh
import math
import os
import json
from palacetoolkit.viz import view_mesh
from palacetoolkit.mesh import (
Entity,
run_meshing_pipeline,
generate_3d_mesh,
refine_near_surfaces
)
Parameters:¶
- l : Patch length along x-axis, specified as a scalar in meters.
- w : Patch width along y-axis, specified as a scalar in meters.
- h : Patch height along z-axis, specified as a scalar in meters.
- l1 : Ground plane length along x-axis, specified as a scalar in meters
- w1 : Ground plane width along y-axis, specified as a scalar in meters
- l2 : Notch length along x-axis, specified as a scalar in meters.
- w2 : Notch width along x-axis, specified as a scalar in meters.
- w3 : Strip line width along y-axis, specified as a scalar in meters.
- air_height : Air box height along z-axis, specified as a scalar in meters.
- air_margin : Air box margin along x and y axes, specified as a scalar in meters.
- freq : Simulation frequency in GHz, specified as a scalar.
- filename : Output mesh filename, specified as a string.
l: float = 0.030
w: float = 0.029
l1: float = 0.06
w1: float = 0.06
l2: float = 0.008
w2: float = 0.003
w3: float = 0.001
h: float = 0.0013
air_height: float = 0.025
air_margin: float = 0.025
freq: float = 3.3
filename: str = "patch_antenna.msh"
wavelength = wavelength = 3e8 / (freq * 1e9)
Initialize the model¶
gmsh.initialize()
gmsh.model.add("patch_antenna")
kernel = gmsh.model.occ
Geometry Construction¶
In this step, we build the physical structure of the patch antenna. We define the substrate, the metallic ground plane, and the antenna patch itself.
Patch Design: We combine the main patch and the feed line, including an inset to help with impedance matching. Excitation: A lumped port is created and positioned to feed the antenna. Domain Setup: We enclose the entire structure in an "air box," which defines the simulation region (the radiation space). Finalizing: We use boolean operations (fragmenting) to ensure all components are properly connected and recognized as a single cohesive model by the solver.
# Total domain bounds
total_xmin = -l1/2 - air_margin
total_xmax = l1/2 + air_margin
total_ymin = -w1/2 - air_margin
total_ymax = w1/2 + air_margin
total_zmax = h + air_height
# Substrate
substrate = kernel.addBox(-l1/2, -w1/2, 0, l1, w1, h)
# Ground plane
ground_plane = kernel.addRectangle(-l1/2, -w1/2, 0, l1, w1)
# Patch definition
main_patch = kernel.addRectangle(-l/2, -w/2, h, l, w)
inset = kernel.addRectangle(-l/2, -w2/2, h, l2, w2)
patch_dimtags, _ = kernel.cut(
[(2, main_patch)],
[(2, inset)],
removeObject=True, removeTool=True
)
kernel.synchronize()
feed_length = (l1 - l)/2 + l2
feed_line = kernel.addRectangle(-l1/2, -w3/2, h, feed_length, w3)
# Our patch
top_conductor, _ = kernel.fuse(
patch_dimtags, [(2, feed_line)],
removeObject=True, removeTool=True
)
kernel.synchronize()
# Gap bewteen the gropund plane and the bottom of the lumped port.
gap = 0
lumped_port = kernel.addRectangle(-l1/2 + gap, -w3/2, 0, h - gap, w3)
kernel.rotate([(2, lumped_port)], -l1/2, 0, 0, 0, 1, 0, -math.pi/2)
kernel.synchronize()
air_box = kernel.addBox(
total_xmin, total_ymin, 0,
total_xmax - total_xmin,
total_ymax - total_ymin,
total_zmax
)
kernel.synchronize()
Info : [ 0%] Difference Info : [ 10%] Difference Info : [ 20%] Difference Info : [ 30%] Difference Info : [ 40%] Difference Info : [ 50%] Difference Info : [ 60%] Difference Info : [ 70%] Difference Info : [ 80%] Difference - Making faces Info : [ 90%] Difference Info : [ 0%] Union Info : [ 10%] Union Info : [ 20%] Union Info : [ 30%] Union Info : [ 40%] Union Info : [ 50%] Union Info : [ 70%] Union Info : [ 80%] Union - Splitting faces Info : Cannot bind existing OpenCASCADE surface 8 to second tag 9 Info : Could not preserve tag of 2D object 9 (->8)
Entities definition and mesh refinement.¶
# Define the entities which later will become the physical groups.
entities = [
Entity("air_box", dim = 3, mesh_order = 2, tags = [air_box]),
Entity("substrate", dim = 3, mesh_order = 1, tags = [substrate]),
Entity("top_conductor", dim = 2, mesh_order= 1, tags = [top_conductor[0][1]]),
Entity("ground_plane", dim = 2, mesh_order = 1, tags = [ground_plane]),
Entity("lumped_port", dim = 2, mesh_order = 0, tags = [lumped_port])
]
# Boolean operations to guarantee a nice mesh, algo it returns the
# physical group map.
pg_map = run_meshing_pipeline(entities)
# Refine near the top conductor and locally the lumped port
refine_near_surfaces(entities[2].dimtags,
wavelength,
ppw_near=50,
ppw_far=30,
set_as_background=True,
local_refinements = {entities[-1].dimtags[0]: 150})
# Mesh sizes
mesh_sizes = {
"substrate": wavelength / 12,
"air_box": wavelength / 4,
"lumped_port": wavelength / 150,
"ground_plane" : wavelength / 10,
"top_conductor": wavelength / 50
}
# Generate the 3d mesh.
generate_3d_mesh(entities, mesh_sizes, filename, optimize = True)
Info : [ 0%] Difference Info : [ 10%] Difference Info : [ 20%] Difference Info : [ 30%] Difference Info : [ 40%] Difference Info : [ 50%] Difference Info : [ 60%] Difference Info : [ 70%] Difference - Filling splits of edges Info : [ 80%] Difference - Adding holes Info : [ 90%] Difference Info : [ 0%] Difference Info : [ 10%] Difference Info : [ 20%] Difference Info : [ 30%] Difference Info : [ 40%] Difference Info : [ 50%] Difference Info : [ 60%] Difference Info : [ 70%] Difference Info : [ 80%] Difference - Splitting faces Info : [ 0%] Difference Info : [ 10%] Difference Info : [ 20%] Difference - Performing Vertex-Face intersection Info : [ 30%] Difference Info : [ 40%] Difference Info : [ 50%] Difference Info : [ 60%] Difference Info : [ 70%] Difference - Filling splits of vertices Info : [ 80%] Difference - Splitting faces Info : [ 0%] Fragments Info : [ 10%] Fragments Info : [ 20%] Fragments Info : [ 30%] Fragments Info : [ 40%] Fragments Info : [ 50%] Fragments Info : [ 60%] Fragments Info : [ 70%] Fragments Info : [ 80%] Fragments Info : [ 90%] Fragments Physical group 'air_box' (dim=3): pg=1, tags=[2] Physical group 'substrate' (dim=3): pg=2, tags=[1] Physical group 'top_conductor' (dim=2): pg=3, tags=[8] Physical group 'ground_plane' (dim=2): pg=4, tags=[7] Physical group 'lumped_port' (dim=2): pg=5, tags=[9] Physical group 'air_box__None' (dim=2): pg=6, tags=[16, 17, 18, 19, 20, 21] Physical group 'air_box__substrate' (dim=2): pg=7, tags=[10, 11, 13, 12, 14, 15] ppw_near=50 ppw_far=30 SizeMax=0.0030 transition=0.0227 global: 12 curves, SizeMin=0.0018 local (2, 9): 4 curves, SizeMin=0.0006 Merged 2 fields with Min → field 5 Info : Meshing 1D... Info : [ 0%] Meshing curve 45 (Line) Info : [ 10%] Meshing curve 46 (Line) Info : [ 10%] Meshing curve 47 (Line) Info : [ 10%] Meshing curve 48 (Line) Info : [ 10%] Meshing curve 49 (Line) Info : [ 20%] Meshing curve 50 (Line) Info : [ 20%] Meshing curve 51 (Line) Info : [ 20%] Meshing curve 52 (Line) Info : [ 20%] Meshing curve 53 (Line) Info : [ 30%] Meshing curve 54 (Line) Info : [ 30%] Meshing curve 55 (Line) Info : [ 30%] Meshing curve 56 (Line) Info : [ 30%] Meshing curve 57 (Line) Info : [ 40%] Meshing curve 58 (Line) Info : [ 40%] Meshing curve 59 (Line) Info : [ 40%] Meshing curve 60 (Line) Info : [ 40%] Meshing curve 61 (Line) Info : [ 50%] Meshing curve 62 (Line) Info : [ 50%] Meshing curve 63 (Line) Info : [ 50%] Meshing curve 64 (Line) Info : [ 50%] Meshing curve 65 (Line) Info : [ 60%] Meshing curve 66 (Line) Info : [ 60%] Meshing curve 67 (Line) Info : [ 60%] Meshing curve 68 (Line) Info : [ 60%] Meshing curve 69 (Line) Info : [ 70%] Meshing curve 70 (Line) Info : [ 70%] Meshing curve 71 (Line) Info : [ 70%] Meshing curve 72 (Line) Info : [ 70%] Meshing curve 73 (Line) Info : [ 80%] Meshing curve 74 (Line) Info : [ 80%] Meshing curve 75 (Line) Info : [ 80%] Meshing curve 76 (Line) Info : [ 80%] Meshing curve 77 (Line) Info : [ 90%] Meshing curve 78 (Line) Info : [ 90%] Meshing curve 79 (Line) Info : [ 90%] Meshing curve 80 (Line) Info : [ 90%] Meshing curve 81 (Line) Info : [100%] Meshing curve 82 (Line) Info : [100%] Meshing curve 83 (Line) Info : [100%] Meshing curve 84 (Line) Info : [100%] Meshing curve 85 (Line) Info : Done meshing 1D (Wall 0.0440041s, CPU 0.044491s) Info : Meshing 2D... Info : [ 0%] Meshing surface 7 (Plane, MeshAdapt) Info : [ 10%] Meshing surface 8 (Plane, MeshAdapt) Info : [ 20%] Meshing surface 9 (Plane, MeshAdapt) Info : [ 30%] Meshing surface 10 (Plane, MeshAdapt) Info : [ 30%] Meshing surface 11 (Plane, MeshAdapt) Info : [ 40%] Meshing surface 12 (Plane, MeshAdapt) Info : [ 50%] Meshing surface 13 (Plane, MeshAdapt) Info : [ 50%] Meshing surface 14 (Plane, MeshAdapt) Info : [ 60%] Meshing surface 15 (Plane, MeshAdapt) Info : [ 70%] Meshing surface 16 (Plane, MeshAdapt) Info : [ 70%] Meshing surface 17 (Plane, MeshAdapt) Info : [ 80%] Meshing surface 18 (Plane, MeshAdapt)
Info : [ 90%] Meshing surface 19 (Plane, MeshAdapt) Info : [ 90%] Meshing surface 20 (Plane, MeshAdapt) Info : [100%] Meshing surface 21 (Plane, MeshAdapt) Info : Done meshing 2D (Wall 0.281701s, CPU 0.282241s) Info : Meshing 3D... Info : 3D Meshing 2 volumes with 1 connected component Info : Tetrahedrizing 6783 nodes... Info : Done tetrahedrizing 6791 nodes (Wall 0.0672971s, CPU 0.06154s) Info : Reconstructing mesh... Info : - Creating surface mesh
Info : - Identifying boundary edges Info : - Recovering boundary Info : Done reconstructing mesh (Wall 0.154576s, CPU 0.139961s) Info : Found volume 2 Info : Found volume 1 Info : It. 0 - 0 nodes created - worst tet radius 14.11 (nodes removed 0 0) Info : It. 500 - 500 nodes created - worst tet radius 2.32991 (nodes removed 0 0)
Info : It. 1000 - 1000 nodes created - worst tet radius 1.90327 (nodes removed 0 0) Info : It. 1500 - 1500 nodes created - worst tet radius 1.69363 (nodes removed 0 0) Info : It. 2000 - 2000 nodes created - worst tet radius 1.55927 (nodes removed 0 0) Info : It. 2500 - 2500 nodes created - worst tet radius 1.4651 (nodes removed 0 0) Info : It. 3000 - 3000 nodes created - worst tet radius 1.38739 (nodes removed 0 0) Info : It. 3500 - 3500 nodes created - worst tet radius 1.32042 (nodes removed 0 0) Info : It. 4000 - 4000 nodes created - worst tet radius 1.26586 (nodes removed 0 0) Info : It. 4500 - 4500 nodes created - worst tet radius 1.22082 (nodes removed 0 0) Info : It. 5000 - 5000 nodes created - worst tet radius 1.18267 (nodes removed 0 0) Info : It. 5500 - 5500 nodes created - worst tet radius 1.14642 (nodes removed 0 0) Info : It. 6000 - 6000 nodes created - worst tet radius 1.117 (nodes removed 0 0)
Info : It. 6500 - 6500 nodes created - worst tet radius 1.09203 (nodes removed 0 0) Info : It. 7000 - 7000 nodes created - worst tet radius 1.06727 (nodes removed 0 0) Info : It. 7500 - 7500 nodes created - worst tet radius 1.04694 (nodes removed 0 0) Info : It. 8000 - 8000 nodes created - worst tet radius 1.02725 (nodes removed 0 0) Info : It. 8500 - 8500 nodes created - worst tet radius 1.00841 (nodes removed 0 0) Info : 3D refinement terminated (15533 nodes total): Info : - 0 Delaunay cavities modified for star shapeness Info : - 0 nodes could not be inserted Info : - 80485 tetrahedra created in 0.379311 sec. (212187 tets/s) Info : 0 node relocations Info : Done meshing 3D (Wall 0.707107s, CPU 0.694023s) Info : Optimizing mesh... Info : Optimizing volume 1 Info : Optimization starts (volume = 4.68e-06) with worst = 0.0303329 / average = 0.787821: Info : 0.00 < quality < 0.10 : 14 elements Info : 0.10 < quality < 0.20 : 51 elements Info : 0.20 < quality < 0.30 : 55 elements Info : 0.30 < quality < 0.40 : 116 elements Info : 0.40 < quality < 0.50 : 159 elements Info : 0.50 < quality < 0.60 : 220 elements Info : 0.60 < quality < 0.70 : 620 elements Info : 0.70 < quality < 0.80 : 1655 elements Info : 0.80 < quality < 0.90 : 2767 elements Info : 0.90 < quality < 1.00 : 1279 elements Info : 120 edge swaps, 0 node relocations (volume = 4.68e-06): worst = 0.153435 / average = 0.798739 (Wall 0.00141821s, CPU 0.00146s) Info : 122 edge swaps, 0 node relocations (volume = 4.68e-06): worst = 0.179231 / average = 0.79884 (Wall 0.00179138s, CPU 0.001871s) Info : 123 edge swaps, 0 node relocations (volume = 4.68e-06): worst = 0.179231 / average = 0.798927 (Wall 0.00214877s, CPU 0.002246s) Info : No ill-shaped tets in the mesh :-) Info : 0.00 < quality < 0.10 : 0 elements Info : 0.10 < quality < 0.20 : 1 elements Info : 0.20 < quality < 0.30 : 0 elements Info : 0.30 < quality < 0.40 : 114 elements Info : 0.40 < quality < 0.50 : 157 elements Info : 0.50 < quality < 0.60 : 211 elements Info : 0.60 < quality < 0.70 : 601 elements Info : 0.70 < quality < 0.80 : 1692 elements Info : 0.80 < quality < 0.90 : 2771 elements Info : 0.90 < quality < 1.00 : 1277 elements Info : Optimizing volume 2
Info : Optimization starts (volume = 0.00031355) with worst = 0.00980293 / average = 0.768839: Info : 0.00 < quality < 0.10 : 176 elements Info : 0.10 < quality < 0.20 : 513 elements Info : 0.20 < quality < 0.30 : 893 elements Info : 0.30 < quality < 0.40 : 1354 elements Info : 0.40 < quality < 0.50 : 2133 elements Info : 0.50 < quality < 0.60 : 3753 elements Info : 0.60 < quality < 0.70 : 8597 elements Info : 0.70 < quality < 0.80 : 17756 elements Info : 0.80 < quality < 0.90 : 26121 elements Info : 0.90 < quality < 1.00 : 12253 elements Info : 1565 edge swaps, 38 node relocations (volume = 0.00031355): worst = 0.0890803 / average = 0.78211 (Wall 0.033204s, CPU 0.03353s) Info : 1574 edge swaps, 38 node relocations (volume = 0.00031355): worst = 0.300014 / average = 0.782184 (Wall 0.0405637s, CPU 0.040983s) Info : No ill-shaped tets in the mesh :-) Info : 0.00 < quality < 0.10 : 0 elements Info : 0.10 < quality < 0.20 : 0 elements Info : 0.20 < quality < 0.30 : 0 elements Info : 0.30 < quality < 0.40 : 1335 elements Info : 0.40 < quality < 0.50 : 2047 elements Info : 0.50 < quality < 0.60 : 3718 elements Info : 0.60 < quality < 0.70 : 8532 elements Info : 0.70 < quality < 0.80 : 17888 elements Info : 0.80 < quality < 0.90 : 26385 elements Info : 0.90 < quality < 1.00 : 12230 elements Info : Done optimizing mesh (Wall 0.131994s, CPU 0.12471s) Info : 15533 nodes 93324 elements Info : Optimizing mesh (Netgen)... Info : Optimizing volume 1 Info : CalcLocalH: 2314 Points 6824 Elements 4622 Surface Elements Info : Remove Illegal Elements Info : 417 illegal tets Info : SplitImprove Info : badmax = 57.3068 Info : 56 splits performed Info : SwapImprove Info : 63 swaps performed Info : SwapImprove2 Info : 0 swaps performed Info : 331 illegal tets Info : SplitImprove Info : badmax = 48.984 Info : 64 splits performed Info : SwapImprove Info : 27 swaps performed Info : SwapImprove2 Info : 10 swaps performed Info : 188 illegal tets Info : SplitImprove Info : badmax = 6583.08 Info : 50 splits performed Info : SwapImprove Info : 17 swaps performed Info : SwapImprove2 Info : 1 swaps performed Info : 59 illegal tets Info : SplitImprove Info : badmax = 1855.43 Info : 20 splits performed Info : SwapImprove Info : 3 swaps performed Info : SwapImprove2 Info : 1 swaps performed Info : 18 illegal tets Info : SplitImprove Info : badmax = 919.193 Info : 6 splits performed Info : SwapImprove Info : 2 swaps performed Info : SwapImprove2 Info : 0 swaps performed Info : 0 illegal tets Info : Volume Optimization Info : CombineImprove Info : 56 elements combined Info : ImproveMesh Info : Total badness = 11475.7 Info : Total badness = 11274.5 Info : SplitImprove Info : badmax = 72.9518 Info : 0 splits performed Info : ImproveMesh Info : Total badness = 11274.5 Info : Total badness = 11264.9 Info : SwapImprove Info : 359 swaps performed Info : SwapImprove2 Info : 0 swaps performed Info : ImproveMesh Info : Total badness = 10590.8 Info : Total badness = 10506.3 Info : CombineImprove
Info : 4 elements combined Info : ImproveMesh Info : Total badness = 10466.1 Info : Total badness = 10460.6 Info : SplitImprove Info : badmax = 19.3753 Info : 0 splits performed Info : ImproveMesh Info : Total badness = 10460.6 Info : Total badness = 10460.2 Info : SwapImprove Info : 41 swaps performed Info : SwapImprove2 Info : 0 swaps performed Info : ImproveMesh Info : Total badness = 10392.7 Info : Total badness = 10368.3 Info : CombineImprove Info : 4 elements combined Info : ImproveMesh Info : Total badness = 10333.5 Info : Total badness = 10330.1 Info : SplitImprove Info : badmax = 17.1911 Info : 0 splits performed Info : ImproveMesh Info : Total badness = 10330.1 Info : Total badness = 10329.9 Info : SwapImprove Info : 11 swaps performed Info : SwapImprove2 Info : 0 swaps performed Info : ImproveMesh Info : Total badness = 10315.2 Info : Total badness = 10308 Info : Optimizing volume 2 Info : CalcLocalH: 14513 Points 72135 Elements 11524 Surface Elements
Info : Remove Illegal Elements Info : 1359 illegal tets Info : SplitImprove Info : badmax = 16.2415 Info : 219 splits performed Info : SwapImprove Info : 240 swaps performed Info : SwapImprove2 Info : 10 swaps performed Info : 826 illegal tets Info : SplitImprove Info : badmax = 186.076 Info : 203 splits performed Info : SwapImprove Info : 75 swaps performed Info : SwapImprove2 Info : 9 swaps performed Info : 314 illegal tets Info : SplitImprove Info : badmax = 1207.17 Info : 94 splits performed Info : SwapImprove Info : 17 swaps performed Info : SwapImprove2 Info : 4 swaps performed Info : 75 illegal tets Info : SplitImprove Info : badmax = 2140.75 Info : 27 splits performed Info : SwapImprove Info : 3 swaps performed Info : SwapImprove2 Info : 2 swaps performed Info : 6 illegal tets Info : SplitImprove Info : badmax = 648.653 Info : 2 splits performed Info : SwapImprove
Info : 0 swaps performed Info : SwapImprove2 Info : 0 swaps performed Info : 0 illegal tets Info : Volume Optimization Info : CombineImprove
Info : 719 elements combined Info : ImproveMesh Info : Total badness = 100235
Info : Total badness = 95286.8 Info : SplitImprove Info : badmax = 22.5746 Info : 2 splits performed Info : ImproveMesh Info : Total badness = 95296.8
Info : Total badness = 94543.2 Info : SwapImprove Info : 4342 swaps performed Info : SwapImprove2
Info : 0 swaps performed Info : ImproveMesh Info : Total badness = 87071.4 Info : Total badness = 84879 Info : CombineImprove
Info : 115 elements combined Info : ImproveMesh Info : Total badness = 83845.7 Info : Total badness = 83576.9 Info : SplitImprove Info : badmax = 15.8183 Info : 0 splits performed Info : ImproveMesh Info : Total badness = 83576.9
Info : Total badness = 83528.6 Info : SwapImprove Info : 677 swaps performed Info : SwapImprove2
Info : 0 swaps performed Info : ImproveMesh Info : Total badness = 83008.3 Info : Total badness = 82581.8 Info : CombineImprove
Info : 33 elements combined Info : ImproveMesh Info : Total badness = 82300.1 Info : Total badness = 82235.7 Info : SplitImprove Info : badmax = 7.18479
Info : 0 splits performed Info : ImproveMesh Info : Total badness = 82235.7 Info : Total badness = 82223.3 Info : SwapImprove
Info : 213 swaps performed Info : SwapImprove2 Info : 0 swaps performed Info : ImproveMesh Info : Total badness = 82141.5
Info : Total badness = 82014.6 Info : Done optimizing mesh (Wall 3.54841s, CPU 3.54573s) Info : Writing 'patch_antenna.msh'... Mesh saved to patch_antenna.msh Info : Done writing 'patch_antenna.msh' Nodes: 15345 Elements: 88452
Mesh visualization¶
view_mesh(filename, transparent_groups= "air_box__None")
Loading mesh file: patch_antenna.msh Groups to render transparent: air_box__None
Mesh loaded successfully with 2 cell blocks
Found 13667 triangles total
Physical group tags in mesh: {3: 'top_conductor', 4: 'ground_plane', 5: 'lumped_port', 6: 'air_box__None', 7: 'air_box__substrate'}
Simulation Configuration¶
We define the key parameters for the electromagnetic simulation here. These settings control the frequency sweep range, material properties (dielectric constant and loss tangent for the substrate), and solver-specific configurations like port impedance and mesh order.
- output_file : output filename for the configuration JSON file
- freq_min : minimum frequency for the simulation (GHz)
- freq_max: maximum frequency for the simulation (GHz)
- freq_step: frequency step for the simulation (GHz)
- eps_r: relative permittivity of the substrate
- loss_tan: loss tangent of the substrate
- port_impedance: characteristic impedance of the lumped port (Ohms)
- solver_order: order of the finite element basis functions for the simulation (e.g., 1 for linear, 2 for quadratic)
output_file: str = "patch_antenna.json"
freq_min: float = 3.0
freq_max: float = 3.5
freq_step: float = 0.005
eps_r: float = 2.2
loss_tan: float = 0.0009
port_impedance: float = 50.0
solver_order: int = 2
Generating the Palace Configuration File¶
Finally, we assemble the simulation parameters into a JSON configuration .
def attr(name):
return [pg_map[name]] if name in pg_map else []
config = {
"Problem": {
"Type": "Driven",
"Verbose": 2,
"Output": "/work/results/patch_antenna/"
},
"Model": {
"Mesh": f"/work/{filename}",
"L0": 1.0,
"Refinement": {}
},
"Domains": {
"Materials": [
{
"Attributes": attr("substrate"),
"Permittivity": eps_r,
"Permeability": 1.0,
"LossTan": loss_tan
},
{
"Attributes": attr("air"),
"Permittivity": 1.0,
"Permeability": 1.0
}
]
},
"Boundaries": {
"PEC": {
"Attributes": attr("ground_plane") + attr("patch")
},
"LumpedPort": [
{
"Index": 1,
"Attributes": attr("lumped_port"),
"R": port_impedance,
"Excitation": True,
"Direction": "+Z"
}
],
"Absorbing": {
"Attributes": attr("farfield"),
"Order": 1
}
},
"Solver": {
"Order": solver_order,
"Device": "CPU",
"Driven": {
"MinFreq": freq_min,
"MaxFreq": freq_max,
"FreqStep": freq_step,
"AdaptiveTol": 0.001
},
"Linear": {
"Type": "Default",
"KSPType": "GMRES",
"Tol": 1.0e-8,
"MaxIts": 200,
"ComplexCoarseSolve": True
}
}
}
script_dir = os.getcwd()
config_path = os.path.join(script_dir, output_file)
with open(config_path, "w") as f:
json.dump(config, f, indent=2)
print(f"Palace config written to {config_path}")
Palace config written to /home/martin/Desktop/PalaceToolkit/docs/examples/patch_antenna.json