Make gpec.h5 a self-contained rerun snapshot#217
Conversation
) Store the full merged TOML, raw equilibrium arrays, and (when enabled) forcing-mode data inside gpec.h5 so a run can be replayed from any directory without the original g-file / CHEASE / auxiliary TOML / forcing inputs. `main("run.h5")` dispatches to `main_from_h5`, which rebuilds the `DirectRunInput` / `InverseRunInput` / `SolovevConfig` / `LargeAspectRatioConfig` directly from the snapshot and hands it to `setup_equilibrium` via the existing `additional_input` channel. The rerun output is written as `<basename>_rerun.h5` to guarantee the source is never overwritten; `--output-dir`, `--output-name`, `--override-file`, and repeatable `--override key=value` CLI flags let users retarget or tweak TOML fields without editing the snapshot. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@claude review, keep it short |
Code ReviewThe overall design is sound: snapshotting raw arrays + merged TOML into Issues1. Test coverage gap: EFIT/CHEASE rerun path has no automated test The new test suite only exercises the Solovev (analytic/ 2. Silent string fallback in # src/Rerun.jl
parsed_val = try
parsed = TOML.parse("_rerun_override_ = $rhs")
parsed["_rerun_override_"]
catch
# Fall back to string if TOML parse fails (e.g., unquoted bare words).
rhs
endA bare 3. Deprecated When Options: either add a 4. No test for The flag is documented and implemented, but there is no test exercising it. Since it follows the same Minor5. File-level "docstring" in """
Rerun support: helpers for saving run inputs into gpec.h5 and replaying them.
...
"""A bare string literal at the top of an |
|
This looks very cool! Going to hold off on reviewing it until #202 is merged in, since there are some conflicts between the two and I've already started reviewing that and working with Calin to get it merged in. Once that's done, I think there's an interesting way to work it into this branch and make the inputs logic concise. Perhaps something like a: |
|
@logan-nc since Calin's code is merged in now, I can take a look at this whenever the merge conflicts are resolved |
|
@jhalpern30 I am out on vacation today and the claude max expires tomorrow. I don't think the merge conflict is serious... can you resolve it or have claude do so for you? don't wait on me to review this |
|
note, this capability definitely needs a good regression test so it doesn't get messed up whenever someone adds a new toml var or other io change (example: @d-burg will add profiles needed for slayer soon) |
I am not currently logged into your claude but I can take a look |
|
ty. I expect the merge conflict is trivial |
…ure/rerun-from-h5
#229) Adds modern coil-geometry inputs alongside the legacy ASCII .dat format: - Analytic generators make_pf_hoop, make_window_pane (axis-aligned, two [R,Z] corners), and make_helical (circular-torus), each producing a CoilSet that flows through the existing currents + apply_transforms (shift/tilt) path. - HDF5 coil I/O: group-based, multi-set, content-tolerant (save_coils_to_h5 / load_coils_from_h5_group! / read_coil_h5 / write_coil_h5) plus dat<->h5 converters. One subgroup per set; unrelated content ignored. - CoilSetConfig gains a `source` discriminator (file/pf_hoop/window_pane/helical) and analytic params; load_coil_sets dispatches via _build_raw_coil_set with .h5/.dat resolved by extension. Legacy .dat behavior unchanged. - Rerun snapshot: a coil run stores the geometry used under input/raw_inputs/coils; main_from_h5 gains --coil-source {forcing-modes|coils} so a run can be replayed from gpec.h5 with no original .dat (recomputing the field from stored geometry, optionally against a new equilibrium). - Fixes a pre-existing stale-key bug in runtests_rerun_from_h5.jl (vacuum/et -> FreeBoundaryStability/eigenmode_energies). - Tests for generators, h5 round-trip/multi-set/junk-tolerance, dispatch, and an end-to-end coil snapshot+replay that deletes the .dat between runs. - Docs: forcing_terms.md coil-source + HDF5 schema sections; coil_geometries README HDF5 schema and corrected toroidal-rotation note. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- CoilSetConfig docstring: `[rad] (...)` parsed as a markdown link; reword to plain prose so makedocs cross-reference check passes. - forcing_terms.md / coil_geometries README: label the HDF5 schema fence as `text` and drop bracket/paren unit annotations. Verified: docs build clean (no missing_docs / invalid-link); regression harness diiid_n1 base vs HEAD shows 30/30 quantities unchanged (.dat coil path identical). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Unify main() so each input source builds a ready (inputs, eq_config, additional_input) and hands it to the renamed main_from_inputs: build_inputs_from_toml and build_inputs_from_h5. This also fixes a latent IMAS bug where main(; dd) never threaded dd into the pipeline body. - equil.toml snapshots are now rerunnable: serialize the built eq_config into inputs[Equilibrium] so gpec_toml_raw is complete (equilibrium_config_to_dict). - parse_override_flag warns instead of silently storing an unparseable value as a String. - Rerun.jl file-level docstring -> comments. - Slim rerun tests to one source + one replay: analytic Solovev replay now diffs all output datasets; direct (EFIT) recovery is checked through the real h5 reader without a pipeline run; override flags and parse logic are covered pipeline-free. Drop the heavy regression-harness rerun cases. - Add an IMAS dd-dispatch regression test. - CLAUDE.md: forbid PR/issue references in source comments. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…control_3d analog) Adds two reusable Analysis.CoilForcing entry points that replicate GPEC's plot_control_3d: - plot_surface_3d(equil; color_by, coil_sets, ...) — the 3D plasma boundary surface, optionally coloured by ANY control-surface output and/or with coils overlaid. One function covers surface-only / +field / +coils / +field+coils; coils-only stays plot_coil_geometry_3d. - control_surface_scalar(equil, modes, n; ...) — inverse-Fourier-transforms spectral modes (b_n, b_n_x, xi_n, …) to a real-space [θ,φ] field, reusing FourierTransforms.inverse and the ν/helicity correction from PerturbedEquilibriumModes (no field recomputation, no Biot-Savart). Conventions: - Shared :RdBu symmetric scale: a blue (+current) coil reads the same colour as the blue (+) field it drives. Sign/handedness chosen and VERIFIED against coil currents so a positive coil produces positive b_n_x directly beneath it (the legacy Python mis-tracks toroidally). - No new Project.toml deps. Coloured 3D surfaces need a PlotlyJS-style backend (already a dep); on GR the tool warns and degrades to an uncoloured surface rather than mis-colouring by Z. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@jhalpern30 — merge conflicts with develop are resolved and this is ready for your review. Unified dispatch (your suggestion).
This also fixed a latent IMAS bug from the #202 merge where Bot review issues — all addressed: equil.toml is more fully/clearly deprecated; Rerun drift coverage — kept lightweight. Instead of heavy regression-harness cases (two full pipeline runs each), the guard lives in the unit suite: one source + one replay with an all-datasets source-vs-replay diff (fires if any new TOML var or IO field isn't snapshotted — e.g. future slayer profiles), plus a pipeline-free direct-EFIT recovery check through the real h5 reader. Net rerun unit-test time ~1 min. Verified: full unit suite green; rerun tests pass; |
…spatch equil.toml has been deprecated for a long time and no example or test ships one; gpec.toml [Equilibrium] is the single supported source. Drop the dead fallback branch in build_inputs_from_toml (and the equilibrium_config_to_dict band-aid that was only there to make that path's snapshot rerunnable). The deeper deprecated EquilibriumConfig(path)/setup_equilibrium(path) overloads in the Equilibrium module are left for a separate cleanup. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…so the field tracks its coil
control_surface_scalar now extends the SFL Fourier modes to the machine
angle via c(θ,φ)=-Re[f(θ)e^{i n ν(θ)}e^{i n·hel·φ}], the exact inverse of
fourier_decompose_bn under φ=-hel(2π ζ + ν). The +ν correction un-shears the
field into a vertical (square-ish) window-pane band — the prior ζ-based
e^{i n φ} left a residual toroidal shear (the 'helical tendrils'). The e^{i n·hel·φ}
makes the toroidal tracking robust for either helicity, and the leading − is a
documented display orientation giving blue-coil↔blue-surface (verified: +coil →
+b_n_x lobe beneath it on DIII-D).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…upplied m range The reconstruction uses only the supplied poloidal modes, so a coil placed within ~one grid cell of the boundary makes b_n near-singular and the truncated series rings (Gibbs — a spurious dip where a single lobe is expected). Documented so users keep a realistic coil standoff or widen the m range. Verified against the direct n=1 harmonic: at a sensible standoff the window-pane b_n_x is a single clean blob peaked on the midplane; only on the separatrix did it split. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…er-matched winding Add make_window_pane_standoff to place a window-pane array by physical standoff distance and poloidal angle off the plasma surface, deriving the frame from surface_point_and_normal instead of explicit R-Z corners. load_coil_sets now receives the equilibrium so the standoff mode can be built from the main forcing pipeline. The standoff tangent is the +90 deg rotation of the outward normal so the poloidal leg runs lower-Z to higher-Z at the outboard midplane, matching make_window_pane's c1->c2 winding. This standardizes the two builders to a single convention: positive current produces positive b_n_x near the coil. Adds a winding-convention test and documents the standoff mode in the TOML example. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jhalpern30
left a comment
There was a problem hiding this comment.
I apologize for the long PR review here, but this touches a lot of the code and I wanted to avoid the extra cruft Claude seems persistent to add. Most of the changes are cosmetic, specifically overly verbose comments, with the exception of a few that are more widereaching such as backwards compatibility and how to carry around the raw_data.
I didn't look too in depth at the forcing terms section since I'm not as familiar with it.
| zmax::Float64 # Maximum Z-coordinate of the computational grid [m]. | ||
| psio::Float64 # The total flux difference |ψ_axis - ψ_boundary| [Weber / radian]. | ||
| bt_sign::Int # Sign of the toroidal field: +1 or -1 (from fpol sign in g-file) | ||
| raw_data::Dict{String,Any} # Raw arrays used to build the splines (for gpec.h5 snapshot/replay) |
There was a problem hiding this comment.
Add this to docstring. Probably no need to duplicate docstring in the comments for this struct
|
|
||
| # Outer constructor: call sites that don't capture raw arrays pass 11 positional args | ||
| # (through bt_sign); raw_data defaults to empty (this equilibrium is then not rerun-snapshottable). | ||
| DirectRunInput(config, sq_in, psi_in, psi_in_xs, psi_in_ys, rmin, rmax, zmin, zmax, psio, bt_sign) = |
There was a problem hiding this comment.
I'm not entirely sure what this is doing / why it needs to be here. I guess this is taking the place of using a @kwdef wrapper on the struct and having raw_data default to none if not specified?
| ro::Float64 # R axis location | ||
| zo::Float64 # Z axis location | ||
| psio::Float64 # Total flux difference |psi_axis - psi_boundary| | ||
| raw_data::Dict{String,Any} # Raw arrays used to build the splines (for gpec.h5 snapshot/replay) |
There was a problem hiding this comment.
Description needs to be in the docstring again
|
|
||
| # Raw ingest data forwarded from DirectRunInput/InverseRunInput for gpec.h5 snapshot/replay. | ||
| # Keys depend on equilibrium kind: "direct", "inverse", or "analytic". | ||
| raw_inputs::Dict{String,Any} |
There was a problem hiding this comment.
docstring. Maybe update your claude.md to note this
| # Rerun snapshot/replay helpers. Depends on the module-level imports above | ||
| # (HDF5, TOML, Equilibrium, ForcingTerms) and the `_BANNER` constant, so this | ||
| # include has to come after them but before `main`, which dispatches into | ||
| # `build_inputs_from_h5` on .h5 inputs. |
There was a problem hiding this comment.
This seems like this issue could be easily avoided by just moving the external using statements to the top of the file above the include statements, and then including include("Rerun.jl") with the rest of the the includes. And then this 4 line comment is unnecessary
| return Equilibrium.build_direct_from_raw(eq_config, raw) | ||
| elseif kind == "inverse" | ||
| return Equilibrium.build_inverse_from_raw(eq_config, raw) | ||
| elseif kind == "analytic" |
There was a problem hiding this comment.
You already explicitly check for analytic before entering this function in build_inputs_from_h5
| # path from the source machine can't trip up later code paths. | ||
| eq_config.eq_filename = "" | ||
|
|
||
| additional_input = if raw_eq["kind"] == "analytic" |
There was a problem hiding this comment.
oh my logic... I had to read this 3 times to get it, I've never seen logic coded like this before. If you think this is best that's fine, but I think this whole section would be much more readable as
if raw_eq["kind"] == "analytic"
if eq_config.eq_type == "lar"
lar_data = get(inputs, "LAR_INPUT", Dict{String,Any}())
additional_input = Equilibrium.LargeAspectRatioConfig(; (Symbol(k) => v for (k, v) in lar_data)...)
else
sol_data = get(inputs, "SOL_INPUT", Dict{String,Any}())
additional_input = Equilibrium.SolovevConfig(; (Symbol(k) => v for (k, v) in sol_data)...)
end
end
elseif raw_eq["kind"] == "direct"
additional_input = Equilibrium.build_direct_from_raw(eq_config, raw)
elseif raw_eq["kind"] == "inverse"
additional_input = Equilibrium.build_inverse_from_raw(eq_config, raw)
else
error("Unknown raw equilibrium kind in gpec.h5: $kind")I think the repeated additional_input is worth the clarity here. And removing the rebuild_equilibrium_input function
| # LAR/Solovev carry their parameters in a separate auxiliary TOML referenced | ||
| # by eq_filename. Merge those parameters into the in-memory `inputs` dict so | ||
| # the snapshot writer emits a self-contained TOML blob. | ||
| merge_auxiliary_eq_toml!(inputs, eq_config) |
There was a problem hiding this comment.
A long term goal might be to just merge this into gpec.toml as a section that only appears if you specify that type of EQ? Seems like this extra toml carrying around is unnecessary
There was a problem hiding this comment.
A general comment on this file - I think its existence is necessary due to the large amount of CLI/override capabilities added, but I think pretty much all of the equilibrium functions can be deleted and in-lined in their respective locations. This will cut the file down a bit
There was a problem hiding this comment.
A suggestion here that you can take or ignore based on how difficult you'd think it'd be to implement - so this PR adds a raw_data struct member to the Input and PlasmaEquilibrium struct, but all this raw_data really contains is the struct data itself in dictionary form? Why don't we just return the input struct itself from the equilibrium setup (or even just make it a part of PlasmaEquilibrium, this would actually be quite easy probably) and then dump that data to the HDF5. I guess you'd still need to load and dump things from an HDF5 so its not perfectly clean, but removes most of the additions to the Equilibrium code
…oor, guard standoff coils against boundary Per NilsLeuthold's review of #278: - make_pf_hoop: raise nsec floor from >=4 to >=361 (default) so a full poloidal loop has at least ~1 deg resolution instead of a near-square. - make_window_pane_standoff: error when a tilted coil would intersect the plasma boundary (clearance = standoff - half*|sin(tilt)| <= 0), the case Nils flagged (90 deg tilt with standoff shorter than half the leg length). - Tests: sub-floor nsec throw; standoff intersection throw + valid case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ure/coil-h5-and-analytic-coils # Conflicts: # src/GeneralizedPerturbedEquilibrium.jl
…ure/coil-h5-and-analytic-coils # Conflicts: # src/Rerun.jl # test/runtests_rerun_from_h5.jl
…alytic-coils ForcingTerms: HDF5 + analytic coil interfaces, with gpec.h5 coil snapshot (issue #229)
|
Thanks for the thorough review — worked through all of it. Summary of how each thread was resolved: Architecture
Comments / structure
Banner (GeneralizedPE:86) — good call, and it's already what the rerun path does: it prints its own banner rather than the normal one, showing Verification
|
… analytic TOML Address PR #217 review: - Replace the raw_data/raw_inputs Dict{String,Any} on DirectRunInput/ InverseRunInput/PlasmaEquilibrium with typed DirectIngest/InverseIngest structs (the serializable node arrays needed to rebuild the splines). The HDF5 writer dumps the struct fields; read_equilibrium_ingest reconstructs them generically. Drops the empty-default outer constructors. - Make every equilibrium kind rerunnable: IMAS and TJ-analytic now capture or regenerate correctly. Replace the lar/else-Solovev replay branch (which misrouted other analytic kinds to Solovev) with ANALYTIC_EQ_SECTIONS plus a shared build_analytic_config used by both the TOML and rerun builders. Remove rebuild_equilibrium_input and the backwards-compat guards. - Embed [SOL_INPUT] directly in gpec.toml (like [TJ_ANALYTIC_INPUT]) and retire the side-car sol.toml files; merge_auxiliary_eq_toml! becomes a deprecation fallback. Migrate all Solovev examples and test fixtures; fix the internal test call sites that bypass main and relied on the side-car. - Remove diff-narration comments, move struct-field descriptions into docstrings, reorder module using/include, slim Rerun.jl. - Add a CHEASE inverse-ingest recovery test; document struct-field convention in CLAUDE.md. Full test suite green; regression harness bit-for-bit identical vs develop on solovev_n1 (21 unchanged) and diiid_n1 (30 unchanged). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… registry Address PR #217 review (maintainability): - Replace the three parallel analytic-dispatch sites (ANALYTIC_EQ_SECTIONS dict, build_analytic_config if/elseif, setup_equilibrium elseif chain) with a single Equilibrium.ANALYTIC_EQ registry of AnalyticEqSpec(section, config_type, run_fn). Both fresh-run and rerun paths now dispatch off it, so adding a new analytic kind is one new row. Drops the unsafe else-defaults-to-TJAnalyticConfig branch. - Extract EFIT_KINDS for the twice-duplicated efit-family list. - Document the ingest positional round-trip contract; sharpen two rerun errors. - Add a guard test asserting every registry entry is well-formed (Dict/String ctors, run_fn method, non-empty section) and that build_analytic_config resolves it, so future drift fails at test time rather than at a user's rerun. Type-stable where it matters: setup_equilibrium still infers a concrete PlasmaEquilibrium and the numerical kernels (sol_run/lar_run/...) stay concretely typed; dynamic dispatch is confined to the once-per-run config boundary behind a function barrier. Regression bit-for-bit identical vs pre-refactor HEAD on solovev_n1 (21) and diiid_n1 (46). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Follow-up (0a7af46): consolidated the analytic-equilibrium dispatch into a single registry. Review flagged that analytic kinds were dispatched across three parallel sites that had to stay in lock-step — the Changes:
Note: splines are not serialized — only the Type stability: Verification:
|
jhalpern30
left a comment
There was a problem hiding this comment.
I cleaned up some minor things myself, but I think two things still need attention regarding backwards compatibility (sorry for the second round).
- Did you mean to add a section for deprecated TOML parameters? This seems unnecessary at this time
- Did you mean to still support an auxiliary equilibrium file? This seems like another one we can just get rid of
| # tangent plane supports the (convex) boundary, so the nearest leg corner's clearance from the | ||
| # boundary along the normal is standoff - half*|sin(tilt)| — the tilt tips the legs toward the | ||
| # surface, while tangential displacement leaves the normal clearance unchanged. | ||
| clearance = standoff - half * abs(sin(deg2rad(poloidal_tilt))) |
There was a problem hiding this comment.
This seems out of place in this PR? Just want to make sure you meant to put this here
There was a problem hiding this comment.
The custom coils in general? Yes, it was a sub-branch that came back into here. Why? The main objective was to be able to re-run coils from an h5 without having to carry around the matching .dat files, which is a necessary condition for this PR to be counted as complete. The custom coils made from toml params was a little missing creep but was a straightforward port of existing OMFIT python code and the only new part was the toml IO, which was tied up in this PR's architecture. So there it is.
If I had more bandwidth, I think you are right that the custom coils should be a separate PR branching off this but landing to develop after this merges. I wish. Next time 👍
| include("Rerun.jl") | ||
| # Drop deprecated [ForceFreeStates] keys (e.g. banded-matrix removal) so legacy gpec.toml files | ||
| # keep parsing instead of throwing an unknown-keyword error. | ||
| function _drop_deprecated_ffs_keys!(table) |
There was a problem hiding this comment.
Is this something we actually want in here? I could see this list getting very long... I thought our approach was just to ignore backwards compatibility until after a first julia release
There was a problem hiding this comment.
I vote we include it hear as the architecture is needed for v2.0.0 and having something there is needed to test whether it works. In the final cleanup of v2.0.0 we can clobber the list to stat fresh if it feels unwieldy. I could be convinced otherwise though... thoughts @jhalpern30 and @matt-pharr?
|
@jhalpern30 to address the top level comments:
|
…readers Make amplitude_imag a required input across the ASCII, HDF5-file, and HDF5-group forcing readers, mirroring amplitude_real, instead of silently defaulting it to zero. Unify the ASCII column terminology on amplitude_real/amplitude_imag to match the HDF5 dataset names across the docstrings, the forcing.dat header, and the example TOML mode-table comments. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
I see. Isn't the point of that article that major versions can break backwards compatibility though, and minor/patch versions must maintain it? I agree backwards compatibility is necessary, but thought is needed to what it means for our case. i.e. in this PR, backwards compatibility is introduced for the banded matrix parameters that I removed in #286 - I would classify this more as "legacy code that was converted last year but no one is/ever really used", so its not like we're preserving someone's workflow, we're just preserving their ability to run with their existing input file without removing a line they probably weren't looking at anyway. And anyone currently working with the Julia code has pretty much signed up for this level of variation in the day to day code, so I don't think we should support this. I would vote to remove it from this PR and make it a new issue/PR for how to intelligently deprecate things such that we can create something that is sustainable in the long term that can deal with more complicated backwards compatible fixes outside of just "ignore this input". |
Exactly. 2.0.0 will break compatibility with fortran v1.5 but will need to maintain compatibility with itself moving forward (i..e 2.0.1, 2.1.0 2.2.0, etc.). Thus, it will very quickly need this deprecation guard. I want it in place so no one goes rogue and deprecates something with no guard. It being there makes it easy to note "you didn't guard your deprecation" in the PR and easy for them to do so instead of replying "what do you mean? how should I?". If you want to move it to another PR and/or champion some other guard technique, I support you doing that. If you don't want to see |
Analytic equilibria (sol/lar/tj_analytic) now resolve their parameters only from the embedded [SOL_INPUT]/[LAR_INPUT]/[TJ_ANALYTIC_INPUT] section of gpec.toml. Every in-repo deck already uses the embedded form and the side-car files were removed, so the deprecation bridge is dead weight pre-release. Remove merge_auxiliary_eq_toml! and its call, the eq_filename side-car fallback in setup_equilibrium (analytic kinds now require their *Config as additional_input, with a clear error otherwise), and the now-orphaned *Config(::String) file constructors. Tighten the surviving *Config(::Dict) docstrings. Drop the side-car hasmethod assertion from the registry test. No numerical change: regression harness solovev_n1 (21/21) and diiid_n1 (46/46) identical local vs branch HEAD. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
ok @jhalpern30 I removed the side-car TOML file support for analytic equilibria (your item 2). Item 1 is in your court. |
Got it. I support |
|
Ok, deprecation is added. The merge conflicts are due to what looks like the half-area weighting, which I don't know much about so I am not going to touch that to avoid breaking it. Once they are resolved, I think this is ready to merge |
…ure/rerun-from-h5
…_vec in favor of the three field weightings b, b_root_area, and b_area
The rerun refactor dropped deprecated analytic side-car TOML support, so
analytic equilibria must carry their parameters in an embedded [SOL_INPUT]
section. The regression_solovev_kinetic_nuzero fixture still pointed at a
sol.toml side-car, so build_analytic_config errored ("requires a [SOL_INPUT]
section") and the full-run test failed. Migrate the Solovev parameters into
gpec.toml (matching the calculated sibling) and drop the dead side-car.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…_field The merge renamed the singular-coupling output resonant_flux -> resonant_area_weighted_field (now b^r = Φ^r/A^r in tesla). The coil-geometry snapshot test in runtests_rerun_from_h5.jl still read the old key, so the HDF5 read returned an empty array and the non-empty / max-amplitude assertions failed. Point the helper at the new key and rename it accordingly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes #171.
Summary
gpec.h5so a run can be replayed from any directory without needing the original g-file / CHEASE / auxiliary TOML (sol.toml/lar.toml) /forcing.dat.main("run.h5")dispatches to a newmain_from_h5replay entry point. It rebuilds aDirectRunInput/InverseRunInputfrom the stored raw arrays, or reconstructs aSolovevConfig/LargeAspectRatioConfigfrom the merged TOML sections, and hands the result tosetup_equilibriumvia the existingadditional_inputchannel — no sentinel path strings.<source_basename>_rerun.h5inpwd()so the source is never overwritten.--output-dir,--output-name,--override-file <toml>, and repeatable--override section.key=valueCLI flags let users retarget the output or tweak TOML fields on the fly.input/ForceFreeStates/*andinput/EQUIL_CONTROL/*mirrors are replaced with a singleinput/gpec_toml_rawstring (full merged TOML), plusinput/raw_inputs/equilibrium/*and (when PE is enabled)input/raw_inputs/forcing_terms/*groups.benchmarks/directory readsinput/ForceFreeStatesorinput/EQUIL_CONTROL. Worth flagging for any downstream notebooks that might.Test plan
test/runtests_rerun_from_h5.jl(self-contained replay matches source bit-for-bit;--override ForceFreeStates.eulerlagrange_tolerance=1e-6propagates; rerun refuses to overwrite its own source)developonsolovev_n1: 20/20 unchanged, zero diffsdevelopondiiid_n1: 26/26 unchanged, zero diffset[1],ep[1],ev[1],mpert,msing, singular ψ/qforcing.dat: source and replay produce bit-for-bit identicalet[1],delta_prime,island_half_width,||resonant flux||from a temp dir that contains onlygpec.h5🤖 Generated with Claude Code