You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
singular/ca_left and singular/ca_right are written to gpec.h5 unconditionally, but
nothing populates them on kinetic runs. The datasets therefore contain uninitialized
memory whenever kinetic_factor > 0.
Filing as a sub-issue of #226 because that effort already rewrites every singular/ write
site (singular/ → SingularSurfaces/), so the guard belongs in the same pass rather than
as a separate drive-by change.
Mechanism
The arrays are allocated with undef and never zeroed: src/ForceFreeStates/ForceFreeStatesStructs.jl:615-616
They are only ever filled by the ideal surface crossings — cross_ideal_singular_surf! (EulerLagrange.jl:594, 631) and the Riccati ideal crossing
(Riccati.jl:1226, 1267).
cross_kinetic_singular_surf! (EulerLagrange.jl) does no asymptotic analysis and never
writes them, so on a kinetic run they keep whatever was on the heap.
They are written out regardless: src/GeneralizedPerturbedEquilibrium.jl:839-840
Running examples/Solovev_kinetic_calculated_example twice with identical code and
diffing singular/ca_left (4096 elements) gives a different number of NaNs each time —
238 in one run, 100 in the other. One ca_right element came back as 7.026e-310, a
subnormal double, which is the classic signature of reading uninitialized memory rather
than a computed value.
This surfaced while validating #365 (on-demand solution derivatives): a develop-vs-branch
comparison flagged these two datasets as differing even though the change is provably
numerics-neutral everywhere else. It is pre-existing on develop and unrelated to that PR.
Impact
Low severity, but genuinely bad behaviour:
Output is non-reproducible run to run for a deterministic calculation, which
undermines any bitwise output comparison (regression harness, benchmark diffing, rerun
from gpec.h5).
Consumers cannot distinguish "not computed" from "computed and happens to be small".
NaNs propagate silently if anything downstream ever starts reading these.
No current consumer is affected: the only reader is compute_delta_prime_from_ca!
(EulerLagrange.jl:16), documented as a stub that is not physically valid and not
called from any integration driver.
Suggested fix
Pick whichever fits the new schema best:
Allocate with zeros instead of undef — one-line, and makes "not computed" read as
zero rather than garbage. Cheapest, and safe since these arrays are small (msing
surfaces).
Summary
singular/ca_leftandsingular/ca_rightare written togpec.h5unconditionally, butnothing populates them on kinetic runs. The datasets therefore contain uninitialized
memory whenever
kinetic_factor > 0.Filing as a sub-issue of #226 because that effort already rewrites every
singular/writesite (
singular/→SingularSurfaces/), so the guard belongs in the same pass rather thanas a separate drive-by change.
Mechanism
undefand never zeroed:src/ForceFreeStates/ForceFreeStatesStructs.jl:615-616cross_ideal_singular_surf!(EulerLagrange.jl:594, 631) and the Riccati ideal crossing(
Riccati.jl:1226, 1267).cross_kinetic_singular_surf!(EulerLagrange.jl) does no asymptotic analysis and neverwrites them, so on a kinetic run they keep whatever was on the heap.
src/GeneralizedPerturbedEquilibrium.jl:839-840Evidence
Running
examples/Solovev_kinetic_calculated_exampletwice with identical code anddiffing
singular/ca_left(4096 elements) gives a different number of NaNs each time —238 in one run, 100 in the other. One
ca_rightelement came back as7.026e-310, asubnormal double, which is the classic signature of reading uninitialized memory rather
than a computed value.
This surfaced while validating #365 (on-demand solution derivatives): a develop-vs-branch
comparison flagged these two datasets as differing even though the change is provably
numerics-neutral everywhere else. It is pre-existing on
developand unrelated to that PR.Impact
Low severity, but genuinely bad behaviour:
undermines any bitwise output comparison (regression harness, benchmark diffing, rerun
from
gpec.h5).No current consumer is affected: the only reader is
compute_delta_prime_from_ca!(
EulerLagrange.jl:16), documented as a stub that is not physically valid and notcalled from any integration driver.
Suggested fix
Pick whichever fits the new schema best:
zerosinstead ofundef— one-line, and makes "not computed" read aszero rather than garbage. Cheapest, and safe since these arrays are small (
msingsurfaces).
ForceFreeStates - IMPROVEMENT - Compute solution derivatives on demand #365 now handles the derivative stores — empty dataset rather than meaningless values.
computedflag / attribute soreaders can tell.
Option 1 plus a note in the dataset docs is probably enough; option 2 is more consistent
with how the rest of the schema is heading.