Skip to content

Record the grid_volume in structure.h5 and test dump/load consistency - #3289

Open
oskooi wants to merge 2 commits into
NanoComp:masterfrom
oskooi:record_grid_volume_dump_structure
Open

Record the grid_volume in structure.h5 and test dump/load consistency#3289
oskooi wants to merge 2 commits into
NanoComp:masterfrom
oskooi:record_grid_volume_dump_structure

Conversation

@oskooi

@oskooi oskooi commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Related to #3282.

Context

dump_structure and load_structure use the same grid_volume at any resolution — but only by construction, and nothing was enforcing it.

Neither Python wrapper builds a gv. Both call through to self.structure (python/simulation.py:2345, :2361), and there is exactly one gv construction path — _init_structure_create_grid_volume (:2053, :1681) — driven by (cell_size, resolution, dimensions, geometry_center, k_point). The (int)(size*a + 0.5) rounding in volone/vol3d/volcyl (src/vec.cpp:904-941) is deterministic, so identical inputs give a bit-identical gv on both sides. The delayed-load path also runs in the right order, after load_chunk_layout.

The gap was that structure::dump wrote no geometric metadata, so structure::load could only validate byte counts. Confirmed empirically that dumping a (5, 4) cell and loading it into a (4, 5) cell at the same resolution succeeded silently with transposed data — the per-chunk ntot (251×201 vs 201×251) is identical, so none of the existing checks fired.

Changes

  • src/vec.cpp:933volcyl tested isinteger(rsize) instead of isinteger(rsize * a). Verified before/after: r=2.5, res=2 now gives 5 pixels with no warning (previously warned), and r=3, res=2.5 gives 8 pixels with the warning (previously silent).
  • src/structure_dump.cppstructure::dump now writes a gv_metadata dataset (dim, a, pixel counts, origin; full double precision), and structure::load compares it against the live gv before reading anything, aborting with a message that names the offending field. Files without the dataset load exactly as before.
  • python/tests/test_dump_load.pytest_dump_load_grid_volume_matches asserts full gv signature equality across a round trip for 1D/2D/3D/cylindrical at resolutions [10, 13, 17.5, 21.3, 33] (all landing on non-integer pixel counts); plus resolution-mismatch, transposed cell, and legacy-file tests.
  • python/tests/test_simulation.pytest_volcyl_pixel_rounding_warning, capturing stderr at the file-descriptor level. The warning tested is from C++ (master_printf_stderrfprintf(stderr, ...) in src/mympi.cpp), not from Python.
  • python/simulation.py + the corresponding block in doc/docs/Python_User_Interface.mdload_structure docstring now states the matching requirements.

Verification

test_dump_load.py: 17 passed single-process and under mpirun -np 2 (which exercises the sharded single_parallel_file=False path). test_simulation.py: 32 passed. C++ tests/dump_load exits 0.

Two Notes:

  • @unittest.skipIf(mp.count_processors() > 1, ...) is used rather than the test_dump_load.py's existing mp.with_mpi() guard, because meep::abort throws RuntimeError whenever count_processors() == 1 even in an MPI build (src/mympic.cpp:248). With the existing guard the new tests would never have run here. The pre-existing test's guard is not changed.
  • fileds::dump/fields::load (src/fields_dump.cpp) have the identical gap — same byte-count-only checks, no gv record. That is not addressed in this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant