Skip to content

feat(palace): expose the Gmsh 3D algorithm and thread counts - #290

Merged
vvahidd merged 2 commits into
gdsfactory:mainfrom
Alisama20:feat/mesher-controls
Oct 1, 2026
Merged

vvahidd merged 2 commits into
gdsfactory:mainfrom
Alisama20:feat/mesher-controls

Conversation

@Alisama20

@Alisama20 Alisama20 commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Stacked on #287: the first commit of this branch is that PR, and only the second one, feat(palace): expose the Gmsh 3D algorithm and thread counts, is new here. Its tests use the mesh hash and the recorded Gmsh options of #287.

#283 asks for the Gmsh thread and algorithm controls to be exposed separately from the Palace solver settings, for a way to keep the mesh identical when that matters, and for the limits to be documented. gsim set none of them: Gmsh ran single-threaded with its default 3D algorithm, and there was no way to change either.

This adds three options to MeshConfig, sim.mesh(), sim.preview() and generate_mesh():

sim.mesh(preset="default", algorithm_3d="delaunay", threads=4, surface_threads=1)
Option Gmsh options set Default
algorithm_3d ("delaunay" or "hxt") Mesh.Algorithm3D = 1 or 10 "delaunay"
threads General.NumThreads, Mesh.MaxNumThreads3D 1
surface_threads Mesh.MaxNumThreads1D, Mesh.MaxNumThreads2D 1

They need a Gmsh with per-dimension thread limits (Mesh.MaxNumThreads1D/2D/3D, which the 4.11.1 manual already lists; I did not check earlier versions, and gmsh is not pinned in pyproject.toml). They are applied right after generate_mesh() initializes Gmsh, and the effective values are recorded with the mesh hash from #287, so the settings behind a hash can be read next to it. A simulation that already has a mesh_config keeps its values unless sim.mesh() overrides them, like the curve-fit and high-order settings.

Defaults change nothing. They are what Gmsh did already, one thread and Delaunay, now set explicitly. On the lumped CPW of the notebooks (135,380 tetrahedra) and on the 800 µm CPW of #283 (90,055), the mesh hash is identical with and without this change.

Which combinations keep the mesh. From the runs behind #283 (Windows 10, Intel i7-9750H, Gmsh 4.15.2; the Apple M4 in the issue shows the same for Delaunay, which is the only algorithm it varied threads for beyond one HXT run):

algorithm_3d threads / surface_threads Same mesh as one thread? Repeats run to run? Meshing time
delaunay 1 / 1, 4 / 1, 12 / 1 yes yes 5.7 s, no gain
delaunay 4 / 4 no no, a different mesh each run 3.5 s
hxt 1 / 1 yes 14.3 s
hxt 4 / 1 no yes, at that count 8.8 s

So the way to get the same mesh whatever the thread count is Delaunay with surface_threads=1, which is the default; it does not make meshing faster. That HXT repeats itself at a fixed thread count was seen on the Windows machine only, in every repeat there; it is worth confirming on another host before relying on it. Parallel surface meshing is the only combination that sped meshing up with Delaunay, and it gives a different mesh each time, also with Mesh.Reproducible=1 and a fixed seed. gsim logs a warning for the two combinations that lose the mesh (surface_threads > 1, and HXT with several threads); the same guidance is in the MeshConfig and generate_mesh docstrings, which the API docs render.

Part of #283.

Test Plan

New tests/palace/test_mesher_controls.py, 18 tests:

  • the defaults, and rejection of threads=0, surface_threads=0 and an unknown algorithm;
  • apply_mesher_options sets every Gmsh option it should, for both algorithms;
  • no warning for Delaunay with 1 or 8 threads, or HXT with one; exactly one for surface_threads=4 and one for HXT with 4 threads;
  • sim.mesh() applies the options and records them in the mesh stats, defaults to one thread, and a simulation with a mesh_config keeps its controls unless sim.mesh() overrides them;
  • Delaunay with serial surfaces gives the same mesh hash for 1 and 4 threads;
  • sim.preview() forwards the options to generate_mesh();
  • the options are set on the gmsh that generate_mesh() itself uses. A first version put this in gmsh_utils, which uses the real Gmsh, and it broke test_generate_mesh_forwards_curve_fit_and_decimation whenever an earlier test had not left Gmsh initialized, because that test replaces generator.gmsh with a fake. It only showed up with all the branches merged, so the helper lives in generator.py now.

I broke each link on purpose (not calling apply_mesher_options, not keeping the previous config, applying the surface count to 3D, not passing threads through, dropping the HXT warning, a wrong HXT code, preview() not forwarding, and using the real Gmsh instead of the generator's) and in every case the matching test failed.

On the real 800 µm CPW of #283, run through sim.mesh() itself:

API call Tets Mesh hash Warnings
no new arguments 90,055 db3edef2cdc04142 0
delaunay, 1 / 1 90,055 db3edef2cdc04142 0
delaunay, 4 / 1 90,055 db3edef2cdc04142 0
delaunay, 12 / 1 90,055 db3edef2cdc04142 0
delaunay, 4 / 4 (twice) 90,018 and 90,000 03d9de97… and 73b45d15… 1 each
hxt, 1 / 1 (twice) 73,007 86335bafc65c9623 both 0
hxt, 4 / 1 (twice) 72,950 37a3afd023a65c05 both 1 each

The classes are the same as in the earlier runs that patched Gmsh directly. The meshes have 90,055 (Delaunay) and 73,007 (HXT) tetrahedra because gsim samples the distance field at 200 points by default, not the 1600 of the recipe in #283, which gives 98,112 and 79,230.

Full suite: 1476 passed, 6 skipped, 4 xpassed (the 1434 that pass on main plus the 24 of #287 and the 18 new tests). pre-commit: all hooks pass.

@github-actions github-actions Bot added the enhancement New feature or request label Sep 29, 2026
@codecov

codecov Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 65.89%. Comparing base (2b7124a) to head (9a84d03).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #290      +/-   ##
==========================================
+ Coverage   65.54%   65.89%   +0.35%     
==========================================
  Files         110      110              
  Lines       16836    16934      +98     
  Branches     3323     3342      +19     
==========================================
+ Hits        11035    11159     +124     
+ Misses       4743     4728      -15     
+ Partials     1058     1047      -11     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The mesh stats could not tell whether two meshes were the same: the
tetrahedron count is not enough, and a hash of the .msh file changes with
Gmsh's node and element numbering. Add gmsh_utils.mesh_hash(), a hash of
node positions, element connectivity and physical groups by name that does
not depend on numbering or element order, and record it in
collect_mesh_stats() with the gsim and Gmsh versions and the effective Gmsh
options that shape the mesh. Show them in print_mesh_stats() and in the
SimulationResult summary. They also reach metadata.json, which exports the
mesh stats.

Part of gdsfactory#283.
gsim left Gmsh at its defaults, so there was no way to choose the 3D
algorithm or the number of threads, both of which decide which mesh comes
out. Add algorithm_3d, threads and surface_threads to MeshConfig, sim.mesh(),
sim.preview() and generate_mesh(), applied right after Gmsh is initialized.
The defaults, Delaunay and one thread, are what Gmsh did already. Log a
warning for the two combinations that do not keep the mesh (parallel surface
meshing, and HXT with several threads), and document which ones do.

Part of gdsfactory#283.
@vvahidd
vvahidd merged commit ac9d388 into gdsfactory:main Oct 1, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants