FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches
0059 — Mixed diagonal block (analytical object, non-analytical self-coupling) is the total in the dense pass only; CSR and block-tridiagonal lose the loop
ID 0059
Class BUG
Severity 2
Status blocked

Models: —

Found: 2026-10-21

Source: found while fixing FHSIM-0058 (feature fhsim-0058-mixed-blocks); that fix left it out of scope.

Decision needed: owner to rule. Options below; each moves the CSR and block-tridiagonal Jacobian of an affected model.

Evidence

A diagonal block is mixed when the object's own OdeJacobian (analytical) and a non-analytical SelfPortCouplingLink both feed it (JacobianAssembler::GetMixedOwnershipBlocks, src/engine/model/JacobianAssembler.cpp, the loop over SelfPortCouplingLinks() at :329).

  • Dense pass: leaveToNumericalPass skips the object's OdeJacobian for that block (:414), so the whole-model finite difference supplies the total D + L (D the own block, L the loop).
  • CSR pass: section 1 takes the object's OdeJacobian (D). Section 3 skips every non-analytical self-coupling (:676-679). L is never added.
  • Block-tridiagonal pass: same, section 1 path A and section 3 (:857-860).

Effect

For such an object the dense block is D + L and the CSR and block-tridiagonal blocks are D. The loop's share is missing.

Reachability: not from normal solver selection. The CSR and block-tridiagonal passes need a pattern from JacobianSparsityAnalyzer::GetJacobianSparsity, which returns -1 for any model with a non-analytical port link or self link (JacobianSparsityAnalyzer.cpp:99, :127), so such a model gets the dense solver. Only a caller that hands its own pattern or block layout reaches it. None is known in-tree; no downstream repo calls these passes.

Possible fix

  1. In the CSR and block-tridiagonal passes, when the diagonal block is mixed, difference the whole-model ODE for the block (as FHSIM-0057 does for a non-analytical object) instead of taking OdeJacobian.
  2. Document that these passes need an all-analytical link set and refuse the model at solver selection (it already does through the -1 above).

Test that would prove it

JacobianFillPathDifferences.DISABLED_MixedDiagonalBlock_PathsAgree asserts CSR and block-tridiagonal equal dense and is red. MixedDiagonalBlock_DenseIsTheTotalAndTheOtherPassesLoseTheLoop pins today's blocks (green). Both in tests/model/JacobianFillPathDifferences_test.cpp.

Risk

Moves the Jacobian of any model that reaches those passes with a mixed diagonal block. None is known in-tree.