Monopole Antenna#

We are going to modify the code of the dipole antenna to create a monopole antenna. The monopole antenna is a half of the dipole antenna, and it is typically mounted above a ground plane.

import gmsh
import math
import os

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

Parameters:

  • filename - Output mesh filename

  • wavelength - Wavelength of the resulting electromagnetic wave

  • arm_length - Length of each antenna arm (default: wavelength/4)

  • arm_radius - Radius of the cylindrical antenna arms (default: arm_length/20)

  • base_length - Length of the ground plane (default: arm_radius * 4)

  • base_width - Width of the ground plane (default: arm_radius * 4)

  • gap_size - Size of the gap between the two arms (port region) (default: arm_length/100)

  • outer_boundary_radius - Radius of the outer spherical boundary (default: 1.5*wavelength)

  • verbose - Gmsh verbosity level (0-5, higher = more verbose)

  • gui - Whether to launch the Gmsh GUI after mesh generation

filename = "monopole.msh"
wavelength = 4.0
base_width = None
base_length = None
arm_length = None
arm_radius = None
gap_size = None
outer_boundary_radius = None
verbose = 5
gui = True

# Set default values
if arm_length is None:
    arm_length = wavelength / 4
if arm_radius is None:
    arm_radius = arm_length / 20
if gap_size is None:
    gap_size = arm_length / 100
if outer_boundary_radius is None:
    outer_boundary_radius = 1.5 * wavelength
if base_width is None:
    base_width = arm_radius * 4
if base_length is None:
    base_length = arm_radius * 4

Initialize gmsh

gmsh.initialize()
kernel = gmsh.model.occ
gmsh.option.setNumber("General.Verbosity", verbose)

# Create a new model. The name dipole is not important. If a model was already added,
# remove it first (this is useful when interactively evaluating this function).
if "monopole" in gmsh.model.list():
    gmsh.model.setCurrent("monopole")
    gmsh.model.remove()
gmsh.model.add("monopole")
# addSphere: The first three parameters are the coordinates of the center, and the last one is the radius.
outer_boundary = kernel.addSphere(0, 0, 0, outer_boundary_radius)

# addCylinder: The first three parameters are the coordinates of the center of the cylinder base,
# the second three defines its axis and the last one its radius.
arm = kernel.addCylinder(0, 0, gap_size / 2, 0, 0, arm_length, arm_radius)

# addRectangle: The first three parameters are the coordinates of the left corner of the rectangle, 
# and the next two define the width and length of the rectangle.
base = kernel.addRectangle(-base_width/2, -base_length/2, -gap_size/2,
                            base_width, base_length)


# Create gap rectangle (port region) and rotate to XZ plane (we need to do this because
# OpenCASCADE does not have a primitive to create a rectangle directly on the XZ
# plane...).
gap_rectangle = kernel.addRectangle(-arm_radius, -gap_size/2, 0, 2*arm_radius, gap_size)
kernel.rotate([(2, gap_rectangle)], 0, 0, 0, 1, 0, 0, math.pi/2)

kernel.synchronize()
# Define the entities which later will generate the physical groups.
entities = [
    Entity("arm",            dim=3, mesh_order=1, tags=[arm]),
    Entity("outer_boundary", dim=3, mesh_order=2, tags=[outer_boundary]),
    Entity("base",           dim=2, mesh_order=1, tags=[base]),
    Entity("port",           dim=2, mesh_order=0, tags=[gap_rectangle]),
]

# Boolean operations to guarantee a nice mesh, algo it returns the
# physical group map.
pg_map = run_meshing_pipeline(entities)

print(entities)

# Refine near the port
refine_near_surfaces(entities[-1].dimtags, 
                     wavelength, 
                     ppw_near=10, 
                     ppw_far=10, 
                     set_as_background=True,
                     local_refinements = {entities[0].dimtags[0]: 10})

# Mesh sizes
mesh_sizes = {}

generate_3d_mesh(entities, mesh_sizes, filename, optimize=False, verbose=False)


# Mesh visualization, rendering transparent the outer boundary.
view_mesh(filename, transparent_groups= "outer_boundary__None")