Coaxial cable mesh#
from palacetoolkit.viz import view_mesh
from palacetoolkit.geometry import extract_tag, xmin, xmax, ymin, ymax, zmin, zmax
import math
import gmsh
Parameters:
filename - the filename to use for the generated mesh.
refinement - measure of how many elements to include, 0 is least
order - the polynomial order of the approximation, minimum 1
inner_diameter_mm - the inner diameter of the cable, in millimeters
outer_diameter_mm - the outer diameter of the cable, in millimeters
length_mm - the length of the cable, in millimeters
verbose - flag to dictate the level of print to REPL, passed to Gmsh
gui - whether to launch the Gmsh GUI on mesh generation
filename : str = "coax.msh"
refinement : int = 2
order : int = 2
inner_diameter_mm : float = 1.6383
outer_diameter_mm : float = 5.461
length_mm : float = 40.0
verbose : int = 5
gui : bool = True
Check that the geometry makes sense.
assert outer_diameter_mm > inner_diameter_mm > 0
assert length_mm > 0
assert refinement >= 0
assert order > 0
Initialization of the model.#
# Creates a reference to the geometry module based on OpenCASCADE (OCC).
kernel = gmsh.model.occ
# Initialize gmsh.
gmsh.initialize()
# Set the verbosity of the output.
gmsh.option.setNumber("General.Verbosity", verbose)
Geometry definitions.#
# Geometry (en mm)
inner_radio = inner_diameter_mm / 2
outer_radio = outer_diameter_mm / 2
# Mesh parameters
n_circum = 4 * 2**refinement
n_length = 4 * 2**refinement
# Geometry
p0 = kernel.addPoint(inner_radio, 0, 0)
p1 = kernel.addPoint(outer_radio, 0, 0)
l0 = kernel.addLine(p0, p1)
Revolve operation - base face generation.#
Rotate the line (l_0) around the z-axis.
First revolve (base_face_0) is made with a 180° degree and n_circum//2 divisions.
Seconde revolve (base_face_1) with a -180° degree and n_circum//2 divisions.
base_face_0 = kernel.revolve(
[(1, l0)], # list of entities to rotate (dim=1 → curve, tag=l0)
0.0, 0.0, 0.0, # origin point of rotation
0.0, 0.0, 1.0, # rotation axis (here, the z-axis)
math.pi, # rotation angle (180°)
[n_circum // 2], # number of divisions in the angular direction
[1.0], # scale factor for the mesh size (1.0 means no scaling)
recombine=True # recombinar las caras resultantes
)
base_face_1 = kernel.revolve(
[(1, l0)],
0.0, 0.0, 0.0,
0.0, 0.0, 1.0,
-math.pi,
[n_circum//2],
[1.0],
recombine=True
)
kernel.revolve returns a list of entities created by the revolution, each one represented as a tuple (dim, tag).
dim is the dimension of the entity (0 for points, 1 for lines, 2 for surfaces, 3 for volumes).
A tag is a unique identifier assigned by Gmsh to each entity created.
We will filter these lists to keep only the surfaces (dim=2) that represent the cylinder faces, discarding any other entities that may have been created during the revolution.
In this case the revolution returns [(1, 4), (2, 1), (1, 2), (1, 3)]. We are only interested in (2, 1), which is the surface created by the revolution, and we discard the lines (1, 4), (1, 2), (1, 3).
base_face_0 = [x for x in base_face_0 if x[0] == 2]
base_face_1 = [x for x in base_face_1 if x[0] == 2]
# Check that there was generated only one face.
assert len(base_face_0) == 1 and len(base_face_1) == 1
Now, we extrude the base faces to get the cylinder.
# Extrude the faces along the z-axis.
cylinder_0 = kernel.extrude(
base_face_0, # List of entities (dim=2, tag)
0.0, 0.0, length_mm, # How much extrusion in (x, y, z)
[n_length], # Divisions in the direction of the extrusion
[1.0], # Scale
recombine=True # recombine faces
)
cylinder_1 = kernel.extrude(
base_face_1,
0.0, 0.0, length_mm,
[n_length],
[1.0],
recombine=True
)
We keep only the tags of the faces and volumes created by the extrusion, filtering by dimension. Remember that cylinder_0 and cylinder_1 are lists of tuples (dim, tag) representing all entities created by the extrusion, including lines, surfaces, and volumes. We are interested only in the faces (dim=2) that form the cylinder end caps, and in the volumes (dim=3) that represent the cylinder body.
base_face_0 = base_face_0[0][1] # Tag of the first surface.
base_face_1 = base_face_1[0][1]
far_face_0 = cylinder_0[0][1]
cylinder_0 = cylinder_0[1][1]
far_face_1 = cylinder_1[0][1]
cylinder_1 = cylinder_1[1][1]
Fragment the geometry to create a valid mesh. This is necessary because we have extruded two faces that share an edge, and we need to ensure that the resulting geometry is properly connected.
# Remove duplicates (if there is any) and preserve the original geometry.
kernel.fragment(kernel.getEntities(), [])
kernel.synchronize()
Info : Rebinding OpenCASCADE point 3
Info : Rebinding OpenCASCADE point 4
Info : Cannot bind existing OpenCASCADE point 3 to second tag 5
Info : Could not preserve tag of 0D object 5 (->3)
Info : Cannot bind existing OpenCASCADE point 4 to second tag 6
Info : Could not preserve tag of 0D object 6 (->4)
Info : Rebinding OpenCASCADE point 7
Info : Rebinding OpenCASCADE point 8
Info : Rebinding OpenCASCADE point 9
Info : Rebinding OpenCASCADE point 10
Info : Cannot bind existing OpenCASCADE point 7 to second tag 11
Info : Could not preserve tag of 0D object 11 (->7)
Info : Cannot bind existing OpenCASCADE point 8 to second tag 12
Info : Could not preserve tag of 0D object 12 (->8)
Info : Cannot bind existing OpenCASCADE point 9 to second tag 13
Info : Could not preserve tag of 0D object 13 (->9)
Info : Cannot bind existing OpenCASCADE point 10 to second tag 14
Info : Could not preserve tag of 0D object 14 (->10)
Info : Rebinding OpenCASCADE curve 2
Info : Rebinding OpenCASCADE curve 3
Info : Rebinding OpenCASCADE curve 4
Info : Rebinding OpenCASCADE curve 5
Info : Rebinding OpenCASCADE curve 6
Info : Cannot bind existing OpenCASCADE curve 4 to second tag 7
Info : Could not preserve tag of 1D object 7 (->4)
Info : Rebinding OpenCASCADE curve 8
Info : Rebinding OpenCASCADE curve 9
Info : Rebinding OpenCASCADE curve 10
Info : Rebinding OpenCASCADE curve 11
Info : Rebinding OpenCASCADE curve 12
Info : Rebinding OpenCASCADE curve 13
Info : Rebinding OpenCASCADE curve 14
Info : Rebinding OpenCASCADE curve 15
Info : Cannot bind existing OpenCASCADE curve 8 to second tag 16
Info : Could not preserve tag of 1D object 16 (->8)
Info : Cannot bind existing OpenCASCADE curve 9 to second tag 17
Info : Could not preserve tag of 1D object 17 (->9)
Info : Rebinding OpenCASCADE curve 18
Info : Cannot bind existing OpenCASCADE curve 11 to second tag 19
Info : Could not preserve tag of 1D object 19 (->11)
Info : Cannot bind existing OpenCASCADE curve 12 to second tag 20
Info : Could not preserve tag of 1D object 20 (->12)
Info : Rebinding OpenCASCADE curve 21
Info : Cannot bind existing OpenCASCADE curve 14 to second tag 22
Info : Could not preserve tag of 1D object 22 (->14)
Info : Cannot bind existing OpenCASCADE curve 15 to second tag 23
Info : Could not preserve tag of 1D object 23 (->15)
Info : Rebinding OpenCASCADE surface 1
Info : Rebinding OpenCASCADE surface 2
Info : Rebinding OpenCASCADE surface 3
Info : Rebinding OpenCASCADE surface 4
Info : Rebinding OpenCASCADE surface 5
Info : Rebinding OpenCASCADE surface 6
Info : Rebinding OpenCASCADE surface 7
Info : Rebinding OpenCASCADE surface 8
Info : Rebinding OpenCASCADE surface 9
Info : Cannot bind existing OpenCASCADE surface 5 to second tag 10
Info : Could not preserve tag of 2D object 10 (->5)
Info : Cannot bind existing OpenCASCADE surface 6 to second tag 11
Info : Could not preserve tag of 2D object 11 (->6)
Info : Rebinding OpenCASCADE surface 12
# Get the boundaries deleting non necessary surfaces
boundaries = []
for cylinder in [cylinder_0, cylinder_1]:
_, local_boundaries = gmsh.model.getAdjacencies(3, cylinder)
local_delete = []
for boundary in local_boundaries:
if boundary not in boundaries:
boundaries.append(boundary)
else:
local_delete.append(boundaries.index(boundary))
# eliminar duplicados
for idx in sorted(local_delete, reverse=True):
del boundaries[idx]
# Delete faces
for face in [base_face_0, base_face_1, far_face_0, far_face_1]:
if face in boundaries:
boundaries.remove(face)
Defining the Physical groups.#
cylinder_group = gmsh.model.addPhysicalGroup(3, [cylinder_0, cylinder_1], -1, "cylinder")
boundary_group = gmsh.model.addPhysicalGroup(2, boundaries, -1, "boundaries")
port1_group = gmsh.model.addPhysicalGroup(2, [base_face_0, base_face_1], -1, "port1")
port2_group = gmsh.model.addPhysicalGroup(2, [far_face_0, far_face_1], -1, "port2")
Mesh settings and generation.#
def _generate_coax_mesh():
# Mesh options
gmsh.option.setNumber("Mesh.MinimumCurveNodes", 2)
gmsh.option.setNumber("Mesh.MinimumCircleNodes", 0)
gmsh.option.setNumber("Mesh.MeshSizeFromPoints", 0)
gmsh.option.setNumber("Mesh.MeshSizeFromCurvature", 0)
gmsh.option.setNumber("Mesh.MeshSizeExtendFromBoundary", 0)
# Set mesh algorithms
gmsh.option.setNumber("Mesh.Algorithm", 6) # frontal (2D)
gmsh.option.setNumber("Mesh.Algorithm3D", 1) # Delaunay (3D)
# Generate 3D mesh
gmsh.model.mesh.generate(3)
# Order of the mesh elements (1 = linear, 2 = quadratic)
gmsh.model.mesh.setOrder(order)
# Save mesh
gmsh.option.setNumber("Mesh.MshFileVersion", 2.2)
gmsh.option.setNumber("Mesh.Binary", 1)
gmsh.write(filename)
if verbose > 0:
print("\nFinished generating mesh. Physical group tags:")
print("Cylinder:", cylinder_group)
print("Boundaries:", boundary_group)
print("Port 1:", port1_group)
print("Port 2:", port2_group)
print()
_generate_coax_mesh()
gmsh.finalize()
view_mesh(filename)
Info : Meshing 1D...
Info : [ 0%] Meshing curve 1 (Line)
Info : [ 10%] Meshing curve 2 (Extruded)
Info : [ 20%] Meshing curve 3 (Extruded)
Info : [ 20%] Meshing curve 4 (Extruded)
Info : [ 30%] Meshing curve 5 (Extruded)
Info : [ 40%] Meshing curve 6 (Extruded)
Info : [ 40%] Meshing curve 8 (Extruded)
Info : [ 50%] Meshing curve 9 (Extruded)
Info : [ 60%] Meshing curve 10 (Extruded)
Info : [ 60%] Meshing curve 11 (Extruded)
Info : [ 70%] Meshing curve 12 (Extruded)
Info : [ 70%] Meshing curve 13 (Extruded)
Info : [ 80%] Meshing curve 14 (Extruded)
Info : [ 90%] Meshing curve 15 (Extruded)
Info : [ 90%] Meshing curve 18 (Extruded)
Info : [100%] Meshing curve 21 (Extruded)
Info : Done meshing 1D (Wall 0.000124882s, CPU 0.000294s)
Info : Meshing 2D...
Info : [ 0%] Meshing surface 1 (Extruded)
Info : [ 20%] Meshing surface 2 (Extruded)
Info : [ 30%] Meshing surface 3 (Extruded)
Info : [ 40%] Meshing surface 4 (Extruded)
Info : [ 50%] Meshing surface 5 (Extruded)
Info : [ 60%] Meshing surface 6 (Extruded)
Info : [ 70%] Meshing surface 7 (Extruded)
Info : [ 80%] Meshing surface 8 (Extruded)
Info : [ 90%] Meshing surface 9 (Extruded)
Info : [100%] Meshing surface 12 (Extruded)
Info : Done meshing 2D (Wall 0.00464383s, CPU 0.00181s)
Info : Meshing 3D...
Info : Meshing volume 1 (Extruded)
Info : Meshing volume 2 (Extruded)
Info : Done meshing 3D (Wall 0.000631244s, CPU 0.000508s)
Info : Optimizing mesh...
Info : Done optimizing mesh (Wall 6.853e-06s, CPU 0s)
Info : 544 nodes 972 elements
Info : Meshing order 2 (curvilinear on)...
Info : [ 0%] Meshing curve 1 order 2
Info : [ 10%] Meshing curve 2 order 2
Info : [ 10%] Meshing curve 3 order 2
Info : [ 20%] Meshing curve 4 order 2
Info : [ 20%] Meshing curve 5 order 2
Info : [ 20%] Meshing curve 6 order 2
Info : [ 30%] Meshing curve 8 order 2
Info : [ 30%] Meshing curve 9 order 2
Info : [ 30%] Meshing curve 10 order 2
Info : [ 40%] Meshing curve 11 order 2
Info : [ 40%] Meshing curve 12 order 2
Info : [ 40%] Meshing curve 13 order 2
Info : [ 50%] Meshing curve 14 order 2
Info : [ 50%] Meshing curve 15 order 2
Info : [ 60%] Meshing curve 18 order 2
Info : [ 60%] Meshing curve 21 order 2
Info : [ 60%] Meshing surface 1 order 2
Info : [ 70%] Meshing surface 2 order 2
Info : [ 70%] Meshing surface 3 order 2
Info : [ 70%] Meshing surface 4 order 2
Info : [ 80%] Meshing surface 5 order 2
Info : [ 80%] Meshing surface 6 order 2
Info : [ 80%] Meshing surface 7 order 2
Info : [ 90%] Meshing surface 8 order 2
Info : [ 90%] Meshing surface 9 order 2
Info : [ 90%] Meshing surface 12 order 2
Info : [100%] Meshing volume 1 order 2
Info : [100%] Meshing volume 2 order 2
Info : Done meshing order 2 (Wall 0.00397241s, CPU 0.003217s)
Info : Writing 'coax.msh'...
Finished generating mesh. Physical group tags:
Cylinder: 1
Boundaries: 2
Port 1: 3
Port 2: 4
Info : Done writing 'coax.msh'
Loading mesh file: coax.msh
Groups to render transparent: ['air_none', 'air_plastic_enclosure']
Mesh loaded successfully with 2 cell blocks
Found 1088 triangles total
Physical group tags in mesh: {2: 'boundaries', 3: 'port1', 4: 'port2'}