|
FhSim
3.1.0
Marine systems simulation
|
| ID | 0020 |
| Class | BUG |
| Severity | 3 |
| Status | blocked |
| Models | Environment |
| Found | 2026-09-22 |
| Decision needed | Change the default to a fixed seed (reproducible by default, a behaviour change for every existing model), or keep the clock default and make the chosen seed loud in the log and the output metadata? |
src/environment/util/EnvironmentSettings.cpp:76:
A model that does not set RandomSeed gets a different seed on every run. The seed feeds the wave-component phases (parameters.cpp, FillRandomPhases) and the default bathymetry.
The second part is what makes this severe rather than merely surprising. When no bathymetry model is named, the default is not a flat bottom: GetBathymetryWaves builds a marenv::seafloor::BathymetryWaves with ten randomly phased structures up to 3 m high. So an input file that says only
does not get a seabed at 55 m. It gets a randomly corrugated seabed averaging 55 m, drawn afresh on every run, and nothing in the file hints at it.
Demonstrated downstream in fhsim_fishery, whose SimObject.CenterWeight regression case takes seafloor forces and sets no seed. Six consecutive runs of the identical binary on the identical input gave C/Pos_0 regression RMS values of 1.264930e+01, 1.259474e+01, 1.273791e+01, 1.265492e+01, 1.267812e+01 and 1.266141e+01. Adding one line, RandomSeed = "1", gives 1.274191e+01 on six runs out of six. That is recorded there as issues 0030 and 0036.
Any model that omits RandomSeed is irreproducible, and the failure mode is quiet: the run succeeds, the numbers are plausible, and only a recorded baseline or a careful re-run reveals it. A regression suite built on such a model is either permanently red or, worse, intermittently red — which is how it presented downstream, where it cost a protracted hunt through heap corruption and threading before the seed was found.
The interaction with the default bathymetry compounds it: a user who writes Bathymetry.Depth reasonably believes they have specified a flat seabed, so they do not suspect randomness is present at all.
Bathymetry.Model = "Waves" to opt into random structures. Bathymetry.Depth alone silently yielding a 3 m-amplitude random seabed is surprising on its own terms, seed or no seed.Recommend 1 and 3 together, with 2 as a cheap addition. They are separable, and 3 is worth doing even if the seed default is left alone.
Run any model that omits RandomSeed twice and compare the output CSVs byte for byte; they differ today. A regression test should assert that two runs of the same input file produce identical output — which is a property worth having in the suite regardless of how this issue is resolved, since it would catch any future source of non-determinism.
Fix 1 or 3 changes the numbers produced by existing models that rely on the defaults, so recorded baselines move. That is a one-off correction rather than a regression — the old numbers were one arbitrary draw each — but it should be done deliberately, re-recording affected baselines in the same commit, and downstream libraries warned.