Coax to waveguide#

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)

Design Parameters#

The antenna geometry and probe feed are defined based on the following physical constraints:

Waveguide (WR-90):

  • 22.86 mm (width)

  • 10.16 mm (height)

  • 40 mm (length)

Probe Feed:

  • Probe Length: 5.89 mm (≈λ/5) to ensure optimal impedance matching.

  • Coaxial Geometry: 3.6 mm (outer diameter) and 1.28 mm (inner diameter).

These parameters serve as the foundation for our geometric construction and subsequent discretization, ensuring the antenna is tuned for its intended frequency of operation.

import gmsh
import math
import os
import json

from palacetoolkit.viz import run_with_scrollable_output, view_mesh
from palacetoolkit.geometry import extract_tag, xmin, xmax, ymin, ymax, zmin, zmax
from palacetoolkit.mesh import refine_near_surfaces
from palacetoolkit.viz import view_mesh
from palacetoolkit.mesh import (
    refine_near_surfaces
)

Parameters:#

  • inner_diameter_mm: Inner diameter of the coaxial cable in millimeters.

  • outer_diameter_mm: Outer diameter of the coaxial cable in millimeters.

  • probe_length_mm : Length of the probe in milimiters.

  • length_mm: Length of the coaxial cable section in millimeters.

  • wg_height: Height of the rectangular waveguide in millimeters.

  • wg_length: Length of the rectangular waveguide in millimeters.

  • wg_width: Width of the rectangular waveguide in millimeters.

  • freq_ghz: Frequency of the wave in gigahertz.

  • verbose: Verbosity level for Gmsh output

  • filename: Name of the output mesh file.

inner_diameter_mm: float = 1.28
outer_diameter_mm: float = 3.6  
probe_length_mm = 5.89
length_mm: float = 5
wg_height: float = 10.16
wg_length: float = 40
wg_width: float = 22.86
freq_ghz: float = 10.0
verbose: int = 2
filename: str = "coax_to_waveguide.msh"
mesh_order = 1
gui = False
order = 1

Initializing the Modeling Environment#

gmsh.initialize()
gmsh.option.setNumber("General.Verbosity", 5)
gmsh.model.add("coax_to_waveguide")
kernel = gmsh.model.occ

Design Parameter Calculation#

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.

c = 3e8  
lamda = (c / (freq_ghz * 1e9)) * 1e3  

inner_radius = inner_diameter_mm / 2
outer_radius = outer_diameter_mm / 2

# y_top is the y-coordinate of the center of the coax probe, 
# which is typically placed at the center of the waveguide height
y_top = wg_height / 2
coax_y_max = y_top + length_mm

# backshort_z is the distance from the probe tip to the backshort plane, 
# which is typically around λ/5 for good impedance matching
backshort_z = lamda / 5

print(f"Wavelength:           {lamda:.2f} mm")
print(f"Probe length:   {probe_length_mm:.2f} mm")
print(f"Backshort Z position: {backshort_z:.2f} mm")
Wavelength:           30.00 mm
Probe length:   5.89 mm
Backshort Z position: 6.00 mm

Geometry Construction and Boolean Operations#

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.

# Waveguide box
waveguide = kernel.addBox(
    -wg_width/2, -wg_height/2, 0,
        wg_width,    wg_height,   wg_length
)

# Outer coax cylinder
outer_cyl = kernel.addCylinder(0, y_top, backshort_z, 
                                0, length_mm, 0, outer_radius)

# Inner conductor
inner_cyl = kernel.addCylinder(0, coax_y_max, backshort_z, 
                                0, -(length_mm + probe_length_mm), 0, inner_radius)

kernel.synchronize()

coax_dielectric, _ = kernel.cut([(3, outer_cyl)], [(3, inner_cyl)],
                                removeObject=True, removeTool=False)

waveguide_cut, _ = kernel.cut([(3, waveguide)], [(3, inner_cyl)],
                                removeObject=True, removeTool= True)

kernel.synchronize()

all_volumes = gmsh.model.getEntities(3)
kernel.fragment(all_volumes, [])
kernel.synchronize()
                                                                                                                                     

Geometric Entity Classification#

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

all_2d_entities = gmsh.model.getEntities(2)
all_3d_entities = gmsh.model.getEntities(3)

def is_interface(x):
    return (math.isclose(ymin(x), y_top, abs_tol=1e-4) and
            math.isclose(ymax(x), y_top, abs_tol=1e-4) and
            math.isclose(xmax(x), outer_radius, abs_tol=1e-4))

def is_coax_port(x):
    return (math.isclose(ymin(x), coax_y_max, abs_tol=1e-4) and
            math.isclose(ymax(x), coax_y_max, abs_tol=1e-4) and
            math.isclose(xmax(x), outer_radius, abs_tol=1e-4))

def is_inner_conductor(x):
    return (math.isclose(xmax(x), inner_radius, abs_tol=1e-4) and 
            not is_interface(x))

def is_outer_conductor(x):
    return (math.isclose(xmax(x), outer_radius, abs_tol=1e-4) and
            ymin(x) >= y_top - 1e-4 and
            not is_coax_port(x) and
            not is_interface(x))

def is_waveport(x):
    return( math.isclose(zmax(x), wg_length, abs_tol=1e-4) and
            math.isclose(zmin(x), wg_length, abs_tol=1e-4))

def is_waveguide_wall(x):
    return (not is_coax_port(x) and
            not is_inner_conductor(x) and
            not is_outer_conductor(x) and
            not is_waveport(x) and 
            not is_interface(x)) 

def is_coax_volume(x):
    return ymin(x) >= y_top - 1e-4

def is_waveguide_volume(x):
    return ymax(x) <= y_top + 1e-4 

coax_port_surfs      = [x for x in all_2d_entities if is_coax_port(x)]
inner_cond_surfs     = [x for x in all_2d_entities if is_inner_conductor(x)]
outer_cond_surfs     = [x for x in all_2d_entities if is_outer_conductor(x)]
waveguide_wall_surfs = [x for x in all_2d_entities if is_waveguide_wall(x)]
waveport_surfs       = [x for x in all_2d_entities if is_waveport(x)]  
coax_vols      = [x for x in all_3d_entities if is_coax_volume(x)]
waveguide_vols = [x for x in all_3d_entities if is_waveguide_volume(x)]

Physical Group Assignment#

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.

pg_coax_port = gmsh.model.addPhysicalGroup(2, [x[1] for x in coax_port_surfs], -1, "coax_port")
pg_probe = gmsh.model.addPhysicalGroup(2, [x[1] for x in inner_cond_surfs], -1, "inner_conductor")
pg_outer_cyl = gmsh.model.addPhysicalGroup(2, [x[1] for x in outer_cond_surfs], -1, "outer_conductor")
pg_waveguide = gmsh.model.addPhysicalGroup(2, [x[1] for x in waveguide_wall_surfs], -1, "waveguide_walls")
pg_waveport = gmsh.model.addPhysicalGroup(2, [x[1] for x in waveport_surfs], -1, "waveport")
pg_dieletric = gmsh.model.addPhysicalGroup(3, [x[1] for x in coax_vols], -1, "coax_volume")
pg_air = gmsh.model.addPhysicalGroup(3, [x[1] for x in waveguide_vols], -1, "waveguide_volume")

pg_map = {
        "coax_port": pg_coax_port,
        "waveport": pg_waveport,
        "waveguide_surface": pg_waveguide,
        "waveguide_volume": pg_air,
        "probe": pg_probe,
        "outer_cyl": pg_outer_cyl,
        "dielectric": pg_dieletric
    }

Mesh Generation, Refinement, and Export#

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.

def _generate_coax_to_waveguide_mesh():
    refine_near_surfaces([(2, extract_tag(x)) for x in inner_cond_surfs + outer_cond_surfs + waveport_surfs + coax_port_surfs], 
                     wavelength= lamda,
                     ppw_near = 50,
                     ppw_far = 20,
                     transition_distance= lamda / 8,
                    )

    gmsh.model.mesh.generate(3)
    gmsh.model.mesh.setOrder(order)
    gmsh.model.mesh.optimize("Netgen")

    gmsh.option.setNumber("Mesh.MshFileVersion", 2.2)
    gmsh.option.setNumber("Mesh.Binary", 0)

    script_dir = os.getcwd()
    output_path = os.path.join(script_dir, filename)
    gmsh.write(output_path)

run_with_scrollable_output(_generate_coax_to_waveguide_mesh, title="Coax-to-waveguide mesh generation", max_lines=10)

if gui:
    gmsh.fltk.run()

gmsh.finalize()
Info    : Meshing 1D...
Info    : [  0%] Meshing curve 1 (Line)
Info    : [ 10%] Meshing curve 2 (Line)
Info    : [ 20%] Meshing curve 3 (Line)
Info    : [ 20%] Meshing curve 4 (Line)
Info    : [ 30%] Meshing curve 5 (Line)
Info    : [ 30%] Meshing curve 6 (Line)
Info    : [ 40%] Meshing curve 7 (Line)
Info    : [ 40%] Meshing curve 8 (Line)
Info    : [ 50%] Meshing curve 9 (Line)
Info    : [ 50%] Meshing curve 10 (Line)
Info    : [ 60%] Meshing curve 11 (Line)
Info    : [ 60%] Meshing curve 12 (Circle)
Info    : [ 70%] Meshing curve 13 (Circle)
Info    : [ 70%] Meshing curve 14 (Line)
Info    : [ 80%] Meshing curve 15 (Line)
Info    : [ 80%] Meshing curve 16 (Circle)
Info    : [ 90%] Meshing curve 17 (Circle)
Info    : [ 90%] Meshing curve 18 (Line)
Info    : [100%] Meshing curve 19 (Circle)
Info    : [100%] Meshing curve 20 (Line)
Info    : Done meshing 1D (Wall 0.0688756s, CPU 0.070071s)
Info    : Meshing 2D...
Info    : [  0%] Meshing surface 1 (Plane, MeshAdapt)
Info    : [ 10%] Meshing surface 2 (Plane, MeshAdapt)
Info    : [ 20%] Meshing surface 3 (Plane, MeshAdapt)
Info    : [ 30%] Meshing surface 4 (Plane, MeshAdapt)
Info    : [ 40%] Meshing surface 5 (Plane, MeshAdapt)
Info    : [ 50%] Meshing surface 6 (Plane, MeshAdapt)
Info    : [ 60%] Meshing surface 7 (Plane, MeshAdapt)
Info    : [ 60%] Meshing surface 8 (Cylinder, MeshAdapt)
Info    : [ 70%] Meshing surface 9 (Plane, MeshAdapt)
Info    : [ 80%] Meshing surface 10 (Cylinder, MeshAdapt)
Info    : [ 90%] Meshing surface 11 (Plane, MeshAdapt)
Info    : [100%] Meshing surface 12 (Cylinder, MeshAdapt)
Info    : Done meshing 2D (Wall 0.128015s, CPU 0.118216s)
Info    : Meshing 3D...
Info    : 3D Meshing 2 volumes with 1 connected component
Info    : Tetrahedrizing 2478 nodes...
Info    : Done tetrahedrizing 2486 nodes (Wall 0.019306s, CPU 0.018991s)
Info    : Reconstructing mesh...
Info    :  - Creating surface mesh
Info    :  - Identifying boundary edges
Info    :  - Recovering boundary
Info    : Done reconstructing mesh (Wall 0.0447786s, CPU 0.040989s)
Info    : Found volume 1
Info    : Found volume 2
Info    : It. 0 - 0 nodes created - worst tet radius 5.10984 (nodes removed 0 0)
Info    : It. 500 - 500 nodes created - worst tet radius 1.38331 (nodes removed 0 0)
Info    : It. 1000 - 1000 nodes created - worst tet radius 1.14555 (nodes removed 0 0)
Info    : It. 1500 - 1500 nodes created - worst tet radius 1.01555 (nodes removed 0 0)
Info    : 3D refinement terminated (4074 nodes total):
Info    :  - 1 Delaunay cavities modified for star shapeness
Info    :  - 0 nodes could not be inserted
Info    :  - 17595 tetrahedra created in 0.0557985 sec. (315331 tets/s)
Info    : 0 node relocations
Info    : Done meshing 3D (Wall 0.135981s, CPU 0.131193s)
Info    : Optimizing mesh...
Info    : Optimizing volume 1
Info    : Optimization starts (volume = 9283.88) with worst = 0.0112082 / average = 0.7543:
Info    : 0.00 < quality < 0.10 :        46 elements
Info    : 0.10 < quality < 0.20 :       131 elements
Info    : 0.20 < quality < 0.30 :       227 elements
Info    : 0.30 < quality < 0.40 :       324 elements
Info    : 0.40 < quality < 0.50 :       526 elements
Info    : 0.50 < quality < 0.60 :      1048 elements
Info    : 0.60 < quality < 0.70 :      2411 elements
Info    : 0.70 < quality < 0.80 :      4363 elements
Info    : 0.80 < quality < 0.90 :      5466 elements
Info    : 0.90 < quality < 1.00 :      2448 elements
Info    : 398 edge swaps, 2 node relocations (volume = 9283.88): worst = 0.230379 / average = 0.768879 (Wall 0.00519735s, CPU 0.005208s)
Info    : 399 edge swaps, 2 node relocations (volume = 9283.88): worst = 0.3 / average = 0.768906 (Wall 0.00605874s, CPU 0.006103s)
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 :       310 elements
Info    : 0.40 < quality < 0.50 :       510 elements
Info    : 0.50 < quality < 0.60 :      1039 elements
Info    : 0.60 < quality < 0.70 :      2404 elements
Info    : 0.70 < quality < 0.80 :      4404 elements
Info    : 0.80 < quality < 0.90 :      5508 elements
Info    : 0.90 < quality < 1.00 :      2448 elements
Info    : Optimizing volume 2
Info    : Optimization starts (volume = 44.3679) with worst = 0.0689716 / average = 0.695575:
Info    : 0.00 < quality < 0.10 :         1 elements
Info    : 0.10 < quality < 0.20 :         5 elements
Info    : 0.20 < quality < 0.30 :        10 elements
Info    : 0.30 < quality < 0.40 :         5 elements
Info    : 0.40 < quality < 0.50 :        28 elements
Info    : 0.50 < quality < 0.60 :        57 elements
Info    : 0.60 < quality < 0.70 :       157 elements
Info    : 0.70 < quality < 0.80 :       228 elements
Info    : 0.80 < quality < 0.90 :       103 elements
Info    : 0.90 < quality < 1.00 :        11 elements
Info    : 16 edge swaps, 0 node relocations (volume = 44.3679): worst = 0.277905 / average = 0.707631 (Wall 0.000170567s, CPU 0.000196s)
Info    : 18 edge swaps, 0 node relocations (volume = 44.3679): worst = 0.322615 / average = 0.709237 (Wall 0.000224197s, CPU 0.000261s)
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 :         4 elements
Info    : 0.40 < quality < 0.50 :        24 elements
Info    : 0.50 < quality < 0.60 :        60 elements
Info    : 0.60 < quality < 0.70 :       160 elements
Info    : 0.70 < quality < 0.80 :       232 elements
Info    : 0.80 < quality < 0.90 :       100 elements
Info    : 0.90 < quality < 1.00 :        11 elements
Info    : Done optimizing mesh (Wall 0.0186066s, CPU 0.018026s)
Info    : 4074 nodes 22560 elements
Info    : Optimizing mesh (Netgen)...
Info    : Optimizing volume 1
Info    : CalcLocalH: 3894 Points 16623 Elements 4592 Surface Elements 
Info    : Remove Illegal Elements 
Info    : 849 illegal tets 
Info    : SplitImprove 
Info    : badmax = 19.2097 
Info    : 132 splits performed 
Info    : SwapImprove  
Info    : 162 swaps performed 
Info    : SwapImprove2  
Info    : 6 swaps performed 
Info    : 533 illegal tets 
Info    : SplitImprove 
Info    : badmax = 1512.76 
Info    : 129 splits performed 
Info    : SwapImprove  
Info    : 64 swaps performed 
Info    : SwapImprove2  
Info    : 8 swaps performed 
Info    : 184 illegal tets 
Info    : SplitImprove 
Info    : badmax = 643.824 
Info    : 53 splits performed 
Info    : SwapImprove  
Info    : 6 swaps performed 
Info    : SwapImprove2  
Info    : 3 swaps performed 
Info    : 47 illegal tets 
Info    : SplitImprove 
Info    : badmax = 4612.07 
Info    : 15 splits performed 
Info    : SwapImprove  
Info    : 1 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 7 illegal tets 
Info    : SplitImprove 
Info    : badmax = 643.824 
Info    : 1 splits performed 
Info    : SwapImprove  
Info    : 0 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 5 illegal tets 
Info    : SplitImprove 
Info    : badmax = 643.824 
Info    : 1 splits performed 
Info    : SwapImprove  
Info    : 0 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 2 illegal tets 
Info    : SplitImprove 
Info    : badmax = 643.824 
Info    : 1 splits performed 
Info    : SwapImprove  
Info    : 0 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 0 illegal tets 
Info    : Volume Optimization 
Info    : CombineImprove 
Info    : 187 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 25994.5 
Info    : Total badness = 24658.1 
Info    : SplitImprove 
Info    : badmax = 26.2601 
Info    : 1 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 24663.8 
Info    : Total badness = 24480.3 
Info    : SwapImprove  
Info    : 1068 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 22625.6 
Info    : Total badness = 22076.3 
Info    : CombineImprove 
Info    : 18 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 21913.7 
Info    : Total badness = 21864.4 
Info    : SplitImprove 
Info    : badmax = 16.4601 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 21864.4 
Info    : Total badness = 21858.7 
Info    : SwapImprove  
Info    : 239 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 21657.3 
Info    : Total badness = 21509.1 
Info    : CombineImprove 
Info    : 13 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 21376.5 
Info    : Total badness = 21357.7 
Info    : SplitImprove 
Info    : badmax = 11.0073 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 21357.7 
Info    : Total badness = 21356.2 
Info    : SwapImprove  
Info    : 107 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 21304 
Info    : Total badness = 21240.1 
Info    : Optimizing volume 2
Info    : CalcLocalH: 218 Points 591 Elements 436 Surface Elements 
Info    : Remove Illegal Elements 
Info    : 170 illegal tets 
Info    : SplitImprove 
Info    : badmax = 15.5651 
Info    : 18 splits performed 
Info    : SwapImprove  
Info    : 18 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 128 illegal tets 
Info    : SplitImprove 
Info    : badmax = 15.5651 
Info    : 16 splits performed 
Info    : SwapImprove  
Info    : 6 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 90 illegal tets 
Info    : SplitImprove 
Info    : badmax = 18.1167 
Info    : 12 splits performed 
Info    : SwapImprove  
Info    : 6 swaps performed 
Info    : SwapImprove2  
Info    : 2 swaps performed 
Info    : 62 illegal tets 
Info    : SplitImprove 
Info    : badmax = 196.553 
Info    : 11 splits performed 
Info    : SwapImprove  
Info    : 6 swaps performed 
Info    : SwapImprove2  
Info    : 1 swaps performed 
Info    : 33 illegal tets 
Info    : SplitImprove 
Info    : badmax = 196.553 
Info    : 8 splits performed 
Info    : SwapImprove  
Info    : 4 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : 7 illegal tets 
Info    : SplitImprove 
Info    : badmax = 196.553 
Info    : 2 splits performed 
Info    : SwapImprove  
Info    : 0 swaps performed 
Info    : SwapImprove2  
Info    : 1 swaps performed 
Info    : 0 illegal tets 
Info    : Volume Optimization 
Info    : CombineImprove 
Info    : 23 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 1527.24 
Info    : Total badness = 1486.36 
Info    : SplitImprove 
Info    : badmax = 19.2346 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 1486.36 
Info    : Total badness = 1485.72 
Info    : SwapImprove  
Info    : 36 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 1438.64 
Info    : Total badness = 1419.21 
Info    : CombineImprove 
Info    : 2 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 1400.97 
Info    : Total badness = 1399.34 
Info    : SplitImprove 
Info    : badmax = 19.8755 
Info    : 1 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 1403.89 
Info    : Total badness = 1401.13 
Info    : SwapImprove  
Info    : 17 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 1381.54 
Info    : Total badness = 1367.13 
Info    : CombineImprove 
Info    : 4 elements combined 
Info    : ImproveMesh 
Info    : Total badness = 1323.25 
Info    : Total badness = 1320.26 
Info    : SplitImprove 
Info    : badmax = 14.5745 
Info    : 0 splits performed 
Info    : ImproveMesh 
Info    : Total badness = 1320.26 
Info    : Total badness = 1320.18 
Info    : SwapImprove  
Info    : 7 swaps performed 
Info    : SwapImprove2  
Info    : 0 swaps performed 
Info    : ImproveMesh 
Info    : Total badness = 1311.37 
Info    : Total badness = 1308.24 
Info    : Done optimizing mesh (Wall 0.739781s, CPU 0.740042s)
Info    : Writing '/home/martin/Desktop/PalaceToolkit/docs/examples/coax_to_waveguide.msh'...
Info    : Done writing '/home/martin/Desktop/PalaceToolkit/docs/examples/coax_to_waveguide.msh'
Coax-to-waveguide mesh generation
  ppw_near=50  ppw_far=20
  SizeMax=1.5000  transition=3.7500
  global: 12 curves, SizeMin=0.6000
view_mesh(filename, transparent_groups= "air_sphere__None")
Loading mesh file: coax_to_waveguide.msh
Groups to render transparent: air_sphere__None

Mesh loaded successfully with 2 cell blocks
Found 4928 triangles total
Physical group tags in mesh: {1: 'coax_port', 2: 'inner_conductor', 3: 'outer_conductor', 4: 'waveguide_walls', 5: 'waveport'}

Generating the Palace Configuration File#

Finally, we assemble the simulation parameters into a JSON configuration file. This file serves as the definitive input for Palace.

palace_config = {
    "Problem": {
        "Type": "Driven",
        "Verbose": 2,
        "Output": "/work/postpro/coax2waveguide"
    },
    "Model": {
        "Mesh": f"/work/coax_to_waveguide.msh", 
        "L0": 1e-3,
        "Refinement": {}
    },
    "Domains": {
        "Materials": [
            {
                "Attributes": [pg_map["waveguide_volume"]],
                "Permittivity": 1.0,
                "Permeability": 1.0
            },
            {
                "Attributes": [pg_map["dielectric"]],
                "Permittivity": 2.2, 
                "Permeability": 1.0
            }
        ]
    },
    "Boundaries": {
        "PEC": {
            "Attributes": [pg_map["waveguide_surface"]] + [pg_map["outer_cyl"]] + [pg_map["probe"]]
        },
        "WavePort": [
            {
                "Index": 2, 
                "Attributes": [pg_map["waveport"]],
                "Mode": 1,
                "Offset": 0.0
            },
            {
                "Index": 1, 
                "Attributes": [pg_map["coax_port"]],
                "Mode": 1,
                "Offset": 0.0,
                "Excitation": True
            }
        ]           
    },
    "Solver": {
        "Order": 2,
        "Device": "CPU",
        "Driven": {

            "MinFreq": 6.0,
            "MaxFreq": 12.0,
            "FreqStep": 0.1,
            "SaveStep": 2,
            "AdaptiveTol": 0.001
        },
        "Linear": {
            "Type": "Default",
            "KSPType": "GMRES",
            "Tol": 1e-08,
            "MaxIts": 200,
            "ComplexCoarseSolve": True
        }
    }
}

with open("coax_to_waveguide.json", 'w') as json_file:
    json.dump(palace_config, json_file, indent=4)
    
print(f"Palace config successfully generated: coax_to_waveguide.json")
Palace config successfully generated: coax_to_waveguide.json