|
FhSim
3.1.0
Marine systems simulation
|
| ID | 0012 |
| Class | BUG |
| Severity | 3 |
| Status | blocked |
Models: —
Found: 2026-10-22, feature step-size-controller (fhsim FHSIM-0066 moved every fhsim_marine_elements cable result)
Decision needed: whether the solver may keep its warm start. Starting from zero, or iterating to the tolerance, changes every result of every model that uses the solver (a baseline move for fhsim_marine_elements, fhsim_fishery models that use coribo, and coribo's own regression).
ConstraintSolver::ComputeDynamicInternal (src/ConstraintSolver/ConstraintSolver.cpp:116-118):
m_Force is the right-hand side. m_SecondDerivatives is a member and holds the answer of the previous call; it is the start guess and is overwritten with the result. The solve stops at 5 iterations or a residual of 1e-6, so the result depends on the start guess. OdeFcn of every SimObject that runs the solver is therefore not a function of (t, x) alone: it depends on how many evaluations came before.
Experiment, 2026-10-22 (fhsim 9f7b2de2, with a scratch variant of FhIntegrator::TryStep_, fhsim_marine_elements tests):
| Variant | fhsim_marine_elements result files that differ from "no extra call" |
|---|---|
one extra OdeFcn before AcceptedStep | 60 of 193 (12 are run-to-run noise) |
one extra OdeFcn after AcceptedStep | 60 |
two extra OdeFcn before AcceptedStep | 60, and 55 of 193 differ from the one-call run |
The same variants leave the idempotent fhsim_fishery models unchanged (only the AcceptedStep readers move). fhsim_coribo's own WinchableCable.ScenarioRunsWithFiniteWinchForce regression passes without the extra call and fails with it (WinchForce RMS 8e1 to 1.8e5).
Test: ConstraintSolverIdempotence.DISABLED_SameStateEvaluatedTwice_GivesTheSameDerivatives (tests/ConstraintSolver_Idempotence_Test.cpp, committed DISABLED_ so the suite stays green): a bent six-element LineStructure evaluated twice at the same (T, X). The largest difference of the state derivatives is 4.04e-13, not 0 (run with --gtest_also_run_disabled_tests).
Second evidence, coribo's own WinchableCable scenario (tests/in/WinchableCable/WinchableCable_in.xml, StableSolver_i, step 0.01, 1 s). The same run with the scratch fhsim variants, WinchForce_3 at t=0.1 (N):
| Variant | WinchForce_3 at t=0.1 |
|---|---|
no extra OdeFcn | -1.246e6 |
one extra OdeFcn after AcceptedStep | -1.048e6 |
one extra OdeFcn before AcceptedStep | -0.994e6 |
two extra OdeFcn before AcceptedStep | -0.994e6 |
An extra evaluation that nothing reads (the one after AcceptedStep) changes the start-up transient by 16 % (-1.246e6 to -1.048e6). That is history dependence through the warm start, in the stiff first 0.1 s where the 5-iteration CG is far from converged. The model settles to 1 to 6 % differences by t=0.4. The last two rows are equal: once a call has converged, a second call returns at once (in the larger fhsim_marine_elements systems five iterations do not converge, and two calls differ from one). The remaining difference between the "before" and "after" rows (5 %) is the stale winch pose read by WinchableCable::AcceptedStep (src/SimObjects/WinchableCable.cpp:70-72), which fhsim FHSIM-0066 corrects. Priority raised to 3 on 2026-10-22: the answer of a stiff start-up depends on how often the model was evaluated.
A model that uses the solver gives different results when the integrator evaluates it an extra time (as AcceptedStep fixes now do), when a Jacobian pass calls OdeFcn, or when the method changes its stage count. Stiff or contact-driven cases amplify the 1e-6 residual: TrawlCable_BedRegression moved a contact transient by 0.05 s and a bridle force by 1480 N at its peak. Results are not reproducible from the model state alone, and a result file cannot be reproduced by a test that evaluates the model once.
iterations, or stop only on the residual). Costs instructions, makes the result independent of the start guess to 1e-6.m_SecondDerivatives around evaluations that must not advance it (the integrator's extra call).OdeFcn of a coribo model depends on the call history.The DISABLED_ test above, enabled. After a fix it must pass with largestDifference == 0.
Every option moves the stored references of the models that use the solver: the fhsim_marine_elements cable, RundDorg and RigidBarCable families and coribo's WinchableCable scenario. Options 1 and 2 change the answer even where nothing evaluates twice.