Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
889 changes: 889 additions & 0 deletions nbs/femwell_cpw.ipynb

Large diffs are not rendered by default.

Binary file added nbs/modal-sim-cpw/mesh.png
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you remove this file?

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
155 changes: 155 additions & 0 deletions nbs/modal-sim-cpw/palace.msh
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you remove this fil?

Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
$MeshFormat
2.2 0 8
$EndMeshFormat
$PhysicalNames
12
1 12 "air__airbox"
1 13 "air__passive"
1 14 "airbox__passive"
1 15 "SiO2__passive"
1 16 "passive__None"
1 17 "SiO2__airbox"
1 18 "SiO2__None"
1 19 "airbox__None"
2 8 "air"
2 9 "passive"
2 10 "SiO2"
2 11 "airbox"
$EndPhysicalNames
Comment on lines +1 to +18
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a generated mesh output checked into the repo. If this file is only an example artifact, consider removing it from version control (or moving it to release assets) and adding it to .gitignore, since generated meshes tend to be large/noisy and can become stale quickly.

Copilot uses AI. Check for mistakes.
$Nodes
36
1 0 -115 14.59
2 0 -115 314.59
3 0 115 314.59
4 0 115 14.59
5 0 -117.5 14.19
6 0 -117.5 14.59
7 0 117.5 14.59
8 0 117.5 14.19
9 0 115 14.19
10 0 -115 14.19
11 0 65 14.19
12 0 25 14.19
13 0 10 14.19
14 0 -10 14.19
15 0 -25 14.19
16 0 -65 14.19
17 0 -115 -2
18 0 115 -2
19 0 -65 11.19
20 0 -25 11.19
21 0 -10 11.19
22 0 10 11.19
23 0 25 11.19
24 0 65 11.19
25 0 -165 -52
26 0 -165 364.59
27 0 165 364.59
28 0 165 -52
29 0 -115 164.5900000000001
30 0 115 164.5900000000001
31 0 -165 156.2949999999998
32 0 -1.13686837721616e-13 364.59
33 0 165 156.2949999999998
34 0 -1.13686837721616e-13 -52
35 0 -5.684341886080802e-15 209.5900000000001
36 0 -1.136868377216161e-15 113.5900000000001
$EndNodes
$Elements
95
1 1 2 12 86 1 29
2 1 2 12 86 29 2
3 1 2 12 89 3 2
4 1 2 12 91 4 30
5 1 2 12 91 30 3
6 1 2 13 92 4 1
7 1 2 14 98 5 6
8 1 2 14 101 7 4
9 1 2 14 102 1 6
10 1 2 14 104 8 7
11 1 2 14 105 8 9
12 1 2 14 108 10 5
13 1 2 15 109 9 11
14 1 2 16 110 12 11
15 1 2 15 111 12 13
16 1 2 16 112 14 13
17 1 2 15 113 14 15
18 1 2 16 114 16 15
19 1 2 15 115 16 10
20 1 2 17 135 17 10
21 1 2 17 137 18 9
22 1 2 17 138 18 17
23 1 2 18 139 16 19
24 1 2 18 140 19 20
25 1 2 18 141 20 15
26 1 2 18 142 14 21
27 1 2 18 143 21 22
28 1 2 18 144 22 13
29 1 2 18 145 12 23
30 1 2 18 146 23 24
31 1 2 18 147 24 11
32 1 2 19 163 25 31
33 1 2 19 163 31 26
34 1 2 19 166 27 32
35 1 2 19 166 32 26
36 1 2 19 168 28 33
37 1 2 19 168 33 27
38 1 2 19 169 28 34
39 1 2 19 169 34 25
40 2 2 8 50 35 36 30
41 2 2 8 50 1 36 29
42 2 2 8 50 3 35 30
43 2 2 8 50 30 36 4
44 2 2 8 50 29 36 35
45 2 2 8 50 29 35 2
46 2 2 8 50 4 36 1
47 2 2 8 50 2 35 3
48 2 2 9 59 11 9 4
49 2 2 9 59 10 16 1
50 2 2 9 59 9 8 7
51 2 2 9 59 6 5 1
52 2 2 9 59 4 9 7
53 2 2 9 59 5 10 1
54 2 2 9 59 14 4 1
55 2 2 9 59 1 15 14
56 2 2 9 59 16 15 1
57 2 2 9 59 12 11 4
58 2 2 9 59 13 12 4
59 2 2 9 59 14 13 4
60 2 2 10 75 23 12 22
61 2 2 10 75 20 21 15
62 2 2 10 75 9 24 18
63 2 2 10 75 10 17 19
64 2 2 10 75 18 22 17
65 2 2 10 75 19 17 20
66 2 2 10 75 18 24 23
67 2 2 10 75 11 24 9
68 2 2 10 75 19 16 10
69 2 2 10 75 12 13 22
70 2 2 10 75 21 14 15
71 2 2 10 75 17 21 20
72 2 2 10 75 22 21 17
73 2 2 10 75 23 22 18
74 2 2 11 101 7 33 30
75 2 2 11 101 6 29 31
76 2 2 11 101 25 17 5
77 2 2 11 101 8 18 28
78 2 2 11 101 5 17 10
79 2 2 11 101 9 18 8
80 2 2 11 101 2 3 32
81 2 2 11 101 31 2 26
82 2 2 11 101 27 3 33
83 2 2 11 101 25 6 31
84 2 2 11 101 8 28 7
85 2 2 11 101 7 28 33
86 2 2 11 101 34 18 17
87 2 2 11 101 28 18 34
88 2 2 11 101 1 29 6
89 2 2 11 101 2 32 26
90 2 2 11 101 31 29 2
91 2 2 11 101 32 3 27
92 2 2 11 101 33 3 30
93 2 2 11 101 30 4 7
94 2 2 11 101 5 6 25
95 2 2 11 101 34 17 25
$EndElements
123 changes: 114 additions & 9 deletions nbs/palace_demo_cpw.ipynb

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion src/gsim/palace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,11 @@
from gsim.palace.driven import DrivenSim
from gsim.palace.eigenmode import EigenmodeSim
from gsim.palace.electrostatic import ElectrostaticSim
from gsim.palace.modal import ModalSim

# Mesh utilities
from gsim.palace.mesh import (
CrossSection,
GroundPlane,
MeshConfig,
MeshPreset,
Expand Down Expand Up @@ -100,11 +102,12 @@
)

# Visualization
from gsim.viz import plot_mesh
from gsim.viz import plot_mesh, view_mesh

__all__ = [
"MATERIALS_DB",
"CPWPortConfig",
"CrossSection",
"DrivenConfig",
"DrivenSim",
"EigenmodeConfig",
Expand All @@ -123,6 +126,7 @@
"MeshConfigModel",
"MeshPreset",
"MeshResult",
"ModalSim",
"NumericalConfig",
"PalacePort",
"PortConfig",
Expand Down Expand Up @@ -154,6 +158,7 @@
"print_stack",
"print_stack_table",
"run_simulation",
"view_mesh",
]


Expand Down
13 changes: 12 additions & 1 deletion src/gsim/palace/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,10 @@ def plot_mesh(
output: str | Path | None = None,
show_groups: list[str] | None = None,
interactive: bool = True,
style: str = "wireframe",
transparent_groups: list[str] | None = None,
) -> None:
"""Plot the mesh wireframe using PyVista.
"""Plot the mesh using PyVista.

Requires mesh() to be called first.

Expand All @@ -356,13 +358,20 @@ def plot_mesh(
Example: ["metal", "P"] to show metal layers and ports.
interactive: If True, open interactive 3D viewer.
If False, save static PNG to output path.
style: ``"wireframe"`` (default) or ``"solid"``.
``"solid"`` renders faces coloured by physical group
with selectable transparent groups.
transparent_groups: Physical-group names rendered at low opacity
when *style="solid"*. Defaults to
``["air_none", "air_plastic_enclosure"]``.

Raises:
ValueError: If output_dir not set or mesh file doesn't exist

Example:
>>> sim.mesh(preset="default")
>>> sim.plot_mesh(show_groups=["metal", "P"])
>>> sim.plot_mesh(style="solid")
"""
from gsim.viz import plot_mesh as _plot_mesh

Expand All @@ -382,4 +391,6 @@ def plot_mesh(
output=output,
show_groups=show_groups,
interactive=interactive,
style=style,
transparent_groups=transparent_groups,
)
2 changes: 2 additions & 0 deletions src/gsim/palace/mesh/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
generate_mesh as generate_mesh_direct,
)
from gsim.palace.mesh.pipeline import (
CrossSection,
GroundPlane,
MeshConfig,
MeshPreset,
Expand All @@ -49,6 +50,7 @@
from . import gmsh_utils

__all__ = [
"CrossSection",
"GeometryData",
"GroundPlane",
"MeshConfig",
Expand Down
34 changes: 26 additions & 8 deletions src/gsim/palace/mesh/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ def generate_mesh(
show_gui: bool = False,
driven_config: DrivenConfig | None = None,
write_config: bool = True,
cross_section: dict[str, float] | None = None,
planar_conductors: bool = False,
) -> MeshResult:
"""Generate mesh for Palace EM simulation.
Expand All @@ -160,6 +161,9 @@ def generate_mesh(
show_gui: Show gmsh GUI during meshing
driven_config: Optional DrivenConfig for frequency sweep settings
write_config: Whether to write config.json (default True)
cross_section: Optional cutting plane specification. Pass a dict
with exactly one of ``{"x": <value>}`` or ``{"y": <value>}``
to slice the 3-D geometry and produce a 2-D mesh instead.
planar_conductors: If True, treat conductors as 2D PEC surfaces

Returns:
Expand Down Expand Up @@ -218,19 +222,33 @@ def generate_mesh(
planar_conductors,
)

# Setup mesh fields
logger.info("Setting up mesh refinement...")
_setup_mesh_fields(
kernel, groups, geometry, stack, refined_mesh_size, max_mesh_size
)
# Handle optional cross-section cutting plane
if cross_section is not None:
logger.info("Creating cutting plane for 2-D cross-section...")
xmin, ymin, xmax, ymax = geometry.bbox
cp_margin = (
max(xmax - xmin, ymax - ymin) + margin + air_margin + 500
)
cut_tag = gmsh_utils.create_cutting_plane(cp_margin, **cross_section)
kernel.synchronize()
Comment on lines +228 to +233
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cp_margin includes an unexplained +500 constant when sizing the cutting plane. This magic number makes the slicing behavior hard to reason about and may be too small/large depending on geometry and stack thickness. Consider deriving the plane extents from the actual 3-D model bounds (including z) or making the extra padding a named parameter/config value with a short rationale.

Copilot uses AI. Check for mistakes.
gmsh_utils.slice_with_plane(cut_tag)
# Set a reasonable global mesh size for the 2-D case
gmsh.option.setNumber("Mesh.MeshSizeMax", max_mesh_size)
else:
# Setup 3-D mesh fields (not applicable after slicing)
logger.info("Setting up mesh refinement...")
_setup_mesh_fields(
kernel, groups, geometry, stack, refined_mesh_size, max_mesh_size
)
Comment on lines +225 to +242
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the cross-section path, refined_mesh_size (and the whole _setup_mesh_fields refinement logic) is skipped, so users will get a globally-sized 2-D mesh regardless of refined_mesh_size/preset. If the intent is still to refine near conductor boundaries in 2-D, consider reusing the boundary-line refinement logic after slicing (or explicitly document/rename parameters to make it clear refinement is not applied for cross-sections).

Copilot uses AI. Check for mistakes.

# Show GUI if requested
if show_gui:
gmsh.fltk.run()

# Generate mesh
logger.info("Generating mesh...")
gmsh.model.mesh.generate(3)
# Generate mesh (2-D for cross-section, 3-D otherwise)
mesh_dim = 2 if cross_section is not None else 3
logger.info("Generating %d-D mesh...", mesh_dim)
gmsh.model.mesh.generate(mesh_dim)

# Collect mesh statistics
mesh_stats = collect_mesh_stats()
Expand Down
Loading
Loading