ALL - REFACTOR - Module-mirroring CamelCase HDF5 schema (issue #226, PR A) - #363
Conversation
Physics-first reorganization of gpec.h5 into 10 CamelCase top-level groups
(Info, Input, Equilibrium, ForceFreeStates, LocalStability, SingularSurfaces,
PerturbedEquilibrium, KineticForces, Tearing, SurfaceGeometries):
- Groups CamelCase at all levels, datasets snake_case, data-driven tokens verbatim.
- splines/ -> Equilibrium/{Profiles,Geometry}; matrices/ -> ForceFreeStates/
EulerLagrangeMatrices/{Ideal,Kinetic}; integration/ -> ForceFreeStates/
Solutions/ForwardIntegration; FreeBoundaryStability/ and EdgeScan/ move under
ForceFreeStates/; slayer/ -> Tearing/ with CamelCase subgroups.
- Galerkin outputs split three ways: solution functions to Solutions/
GalerkinIntegration/Solution, RPEC matching data to .../Match (kept pending a
Galerkin-owner decision on the debug-only drop), per-surface Dp/PEST-3
results consolidated into SingularSurfaces/GalerkinDeltaPrime next to the
ideal delta_prime_matrix and GGJ coefficients.
- KineticForces: records/ -> EnergyIntegrals/, matrices_<method>/ ->
<method>/KineticMatrices/.
- Input echoes flushed (kinetic/, slayer/settings/): inputs live only under
Input/, everything else is derived output. Writer<->Rerun.jl paths locked by
shared H5_* consts.
- Fixed 8 benchmark/example readers of the long-removed vacuum/ group.
- Regression harness: case TOMLs repointed (quantity names unchanged);
extractor gains a LEGACY_PREFIX_MAP fallback so cross-commit comparisons and
--ref-range scans work across the rename boundary; retired only
kinetic_factor (x2 solovev_kinetic cases, group flushed).
- New test/runtests_h5_schema.jl enforces CamelCase group naming on a full-run
output; docs get docs/development/hdf5-conventions.md + refreshed schema
tables.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0129rSTCmYJDBbcH9khHqYnz
|
Full |
|
@matt-pharr please approve, remove or clean-up the |
|
@d-burg @jhalpern30 @priyanshlunia please at least skim the Schema map table above and submit a review confirming that you have. Of course, at least one full diff review is needed... any volunteers? Should be relatively easy to skim since there is no math to check. |
jhalpern30
left a comment
There was a problem hiding this comment.
Only some minor comments. I like the new naming convention
Something I was thinking about is that I think right now, Slayer and Galerkin have their own HDF5 write functions (which take in the existing HDF5 file). I'm wondering if it would simplify some code elsewhere to write other parts of the outputs incrementally too? Would involve tracking down any data we are lugging around for the sole purpose of dumping to HDF5.
No idea if this would simplify things (and it doesn't need to go in this PR), but just a thought
| # path is missing (the output came from a pre-rename ref), the translated legacy path | ||
| # is retried so cross-commit comparisons and --ref-range scans work across the | ||
| # boundary. First matching prefix wins — keep more-specific entries first. | ||
| const LEGACY_PREFIX_MAP = [ |
There was a problem hiding this comment.
This seems like an annoying thing to carry around. IMO could just be a "hey developers, make sure you run your regressions with --force or whatever once to reset your outputs" and make GPEC v2.0.0 just assume this output tree
| using Plots | ||
|
|
||
| # HDF5 group prefixes shared by every reader in this module. | ||
| const PE_SINGULAR_COUPLING = "PerturbedEquilibrium/SingularCoupling/" |
There was a problem hiding this comment.
I don't like this. Its a minor change, but just doing base = "PerturbedEquilibrium/SingularCoupling/" etc. was fine
| # HDF5 paths read back by the file-based rerun (Rerun.jl); shared consts keep the | ||
| # writer and rerun reader from drifting apart. Schema conventions: | ||
| # docs/development/hdf5-conventions.md. | ||
| const H5_INPUT_TOML = "Input/gpec_toml_raw" |
There was a problem hiding this comment.
Not a fan of these consts either, but up to you, I could see it going either way. The whole "keep writer and rerun reader from drifting apart" could just be fixed by ctrl + f when changing things
| @test isempty(bad) | ||
|
|
||
| # Retired/renamed legacy top-level groups must not reappear. | ||
| for legacy in ("info", "input", "equil", "splines", "integration", "locstab", |
There was a problem hiding this comment.
This is a weird test - if I'm getting this right, we run the updated version of the code, which has these names removed, and check if the names are still there? I think just having it do a quick run and check for anything not camel case in the HDF5 is ok
Pros of consolidated h5 writing:
Pros of distributed writing:
Possible balance:
Open question:
Thoughts @matt-pharr @d-burg? |
|
I personally think I like the balanced compromise where components of the h5 write incrementally by module (eq, FFS, then tearing). This is something that would be much easier to do in h5 than it was in the fortran netcdf interface, and we will retain partial results in case of a crash |
priyanshlunia
left a comment
There was a problem hiding this comment.
Looks good to me -- new names are generally more descriptive and easier to parse.
|
Following up on my own comment about incremental per-module writes — I dug into where this actually stands, and it turns out we're most of the way there already. Filed as #374 rather than expanded here; summary of what I found: Module-level staging already exists. PE opens The gap is inside stage 1. The equilibrium solve, ODE integration, Not proposing it for this PR. Two reasons beyond the obvious one that this PR is already approved and the diff is large enough:
Also worth flagging while I'm in this thread, since it affects the merge rather than the review: This PR is currently The three gal_validation ones need a decision rather than a mechanical resolution — those files are gone from develop, so the legacy-path fixes this branch made to them are moot. Same applies to the equivalent fix in #368. Since resolving these changes what would actually land, it's worth a second look at the resolution before merging, even though the approvals are already in. |
Resolutions:
- src/GeneralizedPerturbedEquilibrium.jl: develop's locstab restructuring (bare
`locstab` kwarg + `locstab !== nothing` guard, from the reduce-whole-struct-passing
refactor) combined with this branch's CamelCase names (LocalStability/,
SingularSurfaces/). The merge base used intr.locstab, so neither side is correct
alone; the auto-merged function signature already carries develop's kwarg.
- src/ForceFreeStates/EulerLagrange.jl: develop's rewritten docstring. This branch's
only edit here was euler.h5 -> gpec.h5 inside a sentence develop deleted.
- benchmarks/gal_validation/{gal_beta_scan,gal_epsilon_scan,pfac_study/gal_pfac_scan2d}.jl:
accept develop's deletion (1d30dfb untracked them); this branch's legacy-path edits
to them are moot.
|
Merged current Five conflicts: two content, three modify/delete. 1.
|
Two content conflicts in src/GeneralizedPerturbedEquilibrium.jl, both resolved as develop's structure + this branch's names (same recipe as the previous develop merge): - ForwardIntegration block: develop's singular-coupling bugfix changed dxi_psi's content from du_store[:, :, 1, :] to the (now 3-D) du_store; kept develop's expression under this branch's ForceFreeStates/Solutions/ForwardIntegration/ paths. - FreeBoundaryStability block: develop's vacuum-response-struct refactor replaced ctrl.vac_flag ? vac_data.* with free_energies !== nothing ? free_energies.*; kept develop's guard and fields under this branch's ForceFreeStates/FreeBoundaryStability/ paths. Post-merge checks: package loads; no conflict markers; repo grep confirms no legacy lowercase h5 paths reintroduced. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0129rSTCmYJDBbcH9khHqYnz
- Fix the last stale legacy-path tokens: the user-visible serial-EL @info log and a comment in Riccati.jl still said integration/xi_*; the populate_dense_xi docstring and use_parallel comment cited dead integration/singular/vacuum paths (docstring also trimmed to house style). - Repoint four dead tracked h5paths in gal_resistive_diiid's PE sibling case (gal_resistive_pe): resonant_flux/penetrated_field/C_resonant_flux leaves were renamed to *_area_weighted_field in the Pharr field-representation change but this case was missed then — they extracted as permanently missing. Labels updated to field terminology; quantity names unchanged. - Unit-test the data-driven whitelist in _group_name_ok directly (method tokens, Surface_<k>, Input/ raw names) — the full-run walk only exercises an ideal deck where none of those branches fire. - Scope the naming rules in hdf5-conventions.md to gpec.h5 (the harness's synthetic ggj/* fixture is not subject to them). - Nits: ASCII-tree column alignment in the PE writer docstring; modernize a retired-path comment in diiid_n1.toml and drop its stale PR reference. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0129rSTCmYJDBbcH9khHqYnz
Per review discussion: - Drop the regression-extractor legacy-path fallback (LEGACY_PREFIX_MAP): schema renames are clean breaks everywhere. Cross-boundary harness comparisons now rely on cached pre-rename quantities (stored by name); fresh extraction of pre-rename outputs reports missing, and developers re-baseline old refs with --force when they need that history. Conventions doc and CLAUDE.md pointer updated to state the new policy. - Revert the Analysis/PerturbedEquilibrium module path consts to the inline base-string style. - Drop the H5_* writer/rerun shared consts; paths are inlined again in both write_outputs_to_HDF5 and Rerun.jl with cross-reference comments marking the mirrored pair. - Simplify runtests_h5_schema.jl: the CamelCase walk already forbids every lowercase legacy group, so the 16-name absence loop is replaced by targeted asserts on the two moved CamelCase groups (FreeBoundaryStability, EdgeScan). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0129rSTCmYJDBbcH9khHqYnz
|
Branch updated: 1. Merge of current develop (
|
Replace the use_riccati / use_parallel / parallel_threads / populate_dense_xi flag set with a single integrator = "forward" | "riccati" | "galerkin" key plus an nchunks knob, per the ForceFreeStates modularization plan (PR 1 of 5). - Delete the standalone serial-Riccati driver and the populate_dense_xi dense-xi re-run; no integration result is merged with another. - Rename serial_eulerlagrange_integration -> forward_eulerlagrange_integration and give the STRIDE propagator driver the freed riccati_ name. - Chunk sizing no longer reads Threads.nthreads(), so Riccati outputs are identical at any thread count; nchunks is the only tunable and clamps up to the singular-surface floor with a warning. - Kinetic runs now error on the Riccati path rather than silently mis-crossing. - The four retired keys join _DEPRECATED_FFS_KEYS and the toml-no-deprecated-keys hook, so old decks and gpec.h5 replays warn and continue. - New examples/DIIID-like_riccati_deltaprime_example plus the diiid_n1_riccati regression case keep the delta-prime matrix covered once the DIIID-like deck moves to the forward integrator. Verified on origin/develop: full suite 59 testsets / 2044 assertions / 0 failures; docs build clean; harness diiid_n1, solovev_n1 and diiid_slayer_n1 all unchanged; delta-prime bit-identical between -t 1 and -t 4. REFACTOR_PLAN.md is amended in the same commit: #363 and #345 merged before this sequence branched, so the plan now records that it builds on the new HDF5 schema. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Summary
PR A of two stacked PRs closing #226: physics-first restructure of the
gpec.h5schema into 10 CamelCase top-level groups, plus the input-echo flush. PR B (self-describing metadata:long_name/units/dimension scales) follows, stacked on this branch. The settled convention is codified in the newdocs/development/hdf5-conventions.mdand enforced by the newtest/runtests_h5_schema.jl.Governing principle: the schema must be intuitive to a plasma physicist who is not a developer of this code. Groups are CamelCase at all levels, datasets snake_case, data-driven tokens (coil sets, method names, scan indices) verbatim, and inputs live only under
Input/— every other group is derived output.Schema map (old → new)
info/,input/,equil/,locstab/Info/,Input/(RawInputs/{Equilibrium,ForcingTerms,Coils}),Equilibrium/,LocalStability/splines/{profiles,rzphi}Equilibrium/{Profiles,Geometry}integration/ForceFreeStates/Solutions/ForwardIntegration/galerkin/solution/,galerkin/msingForceFreeStates/Solutions/GalerkinIntegration/{Solution/,msing}galerkin/match/**ForceFreeStates/Solutions/GalerkinIntegration/Match/**(kept — see below)galerkin/{delta,pest3_*,sing_*,di,alpha,delta_coil}SingularSurfaces/GalerkinDeltaPrime/*(Δ′ consolidates by physics next todelta_prime_matrix+ GGJ coefficients)matrices/{ideal,kinetic}ForceFreeStates/EulerLagrangeMatrices/{Ideal,Kinetic}FreeBoundaryStability/,EdgeScan/ForceFreeStates/{FreeBoundaryStability,EdgeScan}/singular/,singular/kinetic/SingularSurfaces/,SingularSurfaces/Kinetic/perturbed_equilibrium/*PerturbedEquilibrium/{ForcingModes,Response,ResponseMatrices,SingularCoupling,Energies}kinetic_forces/<m>/records,kinetic_forces/matrices_<m>KineticForces/<m>/{EnergyIntegrals,KineticMatrices}slayer/*Tearing/{PerSurface(/DpMatrix),Roots,LayerWidths,Diagnostics/{ValidRoots,Poles,FilteredRoots},Scan/Surface_<k>}kinetic/,slayer/settings/Input/gpec_toml_raw+ rerun)Reserved for the upcoming integrator options (documented, not written):
ForceFreeStates/Solutions/RiccatiIntegration/.kinetic/andslayer/settings/are deleted (pure input echoes;Rerun.jlreconstructs all control structs fromInput/gpec_toml_raw).galerkin/match/is KEPT (renamed toGalerkinIntegration/Match/), reversing the earlier "debug-only, drop it" decision: PR InnerLayer (GGJ) - NEW - rotated-ray collocation backend (:ray), robust to |Q| ~ 500 #323 deliberately added new datasets there days ago (Inner/b_<i>,InnerParams/{E,F,G,H,K,M,taua,taur,v1},bpen, …). The drop — and the question of re-homingbpen/InnerParams— is deferred to its own PR after consulting the Galerkin owner.kinetic_factor(×2 solovev_kinetic cases — group flushed). The 3galerkin/match/*tracked quantities are repointed, not retired.vacuum/group (et/ep/ev/wt0→ForceFreeStates/FreeBoundaryStability/*) — these were already broken on develop.Back-compat
Clean break in
src/readers. The regression-harness extractor gains aLEGACY_PREFIX_MAPfallback (new→old, tried when the new path is missing) so--refscomparisons and--ref-rangebisects keep working across the rename boundary — exercised by the develop side of the harness run below.Regression harness (mandatory gate) — zero numerical movement
regress --cases <all 12> --refs develop,local: every surviving quantity OK with 0.0e+00 diff.*_flux/penetrated_fieldtracks — N/A on develop too, untouched by this PR)Other verification
test/runtests_h5_schema.jl: full Solovev run → all group paths CamelCase/whitelisted, legacy top-level groups absent (20/20).runtests_rerun_from_h5.jl: bit-for-bit whole-schema source↔replay round-trip passes;runtests_slayer_runner.jl62/62;runtests_coils.jl,runtests_fullruns.jlpass.Coordination
This PR is mechanical but wide — it will conflict textually with open PRs touching writers (#354, #345, #339, #318). Please review + merge promptly and warn authors to rebase; PR B is additive/low-conflict.
Post-merge: re-run the harness once on develop to cache baselines at the merge commit; close #226 citing the conventions doc.
This PR must not be merged until a third-party human reviewer has approved it — non-negotiable project policy.
🤖 Generated with Claude Code
https://claude.ai/code/session_0129rSTCmYJDBbcH9khHqYnz