FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches
0005 — TrawlDoorAddedFoil FoilEnergyConsumed output is always zero
ID 0005
Class BUG
Severity 2
Status blocked
Models Trawl/TrawlDoorAddedFoil
Found 2026-09-15 audit (a7d080d)
Decision needed Define the integrand and sign of "energy spent controlling the foil" (which adds a state), or delete the FoilEnergyConsumed port. Depends on FISH-0004.

Evidence

src/trawl/TrawlDoorAddedFoil.cpp:11 (constructor) sets m_foilEnergyConsumed = 0;. src/trawl/TrawlDoorAddedFoil.cpp:44-60 — the output port function returns it, its body otherwise a commented-out block of unrelated roll-angle arithmetic:

const double* TrawlDoorAddedFoil::OutFoilEnergyConsumed(const double dT, const double* const adX)
{
/*const double* adQuaternions = adX + m_IStateQuater;
... */
return &m_foilEnergyConsumed;
}
const double * OutFoilEnergyConsumed(const double dT, const double *const adX)
Output port returning the foil energy consumption.

grep -n m_foilEnergyConsumed src/trawl/TrawlDoorAddedFoil.cpp finds only those two lines; the member is never accumulated. The port is registered at src/trawl/TrawlDoorAddedFoil.cpp:32 and documented at src/trawl/TrawlDoorAddedFoil.h:50 as "The energy consumed by controlling the foil." Nor is there any state for it: the class adds no AddState call, so unlike Actuator — which registers an Energy state and integrates max(speed * Force, 0) — there is nowhere for an accumulated energy to live across steps.

Effect

The stated purpose of this class is to score a proposed control concept on actuation cost as well as on gear geometry. That score is identically zero for every control law, so any comparison between concepts is uninformative on exactly the axis the class was added to measure.

Possible fix

The shape is clear from the sibling that does it right — Actuator (src/trawl/Actuator.cpp): register a state and integrate positive mechanical power into it in OdeFcn. Concretely:

  1. m_IStateEnergy = creator->AddState("FoilEnergy", 1); in the constructor, initialised to 0.
  2. In OdeFcn, adXDot[m_IStateEnergy] = max(power, 0.0), with power the product of the foil actuation rate and the hydrodynamic load resisting it — which requires FISH-0004 first, since today no foil load is computed.
  3. OutFoilEnergyConsumed returns adX + m_IStateEnergy rather than a member, so the value is a genuine state and survives step rejection. Delete the commented-out roll-angle block while there.

The alternative: delete the port and the header line, so a model asking for foil cost gets a load error instead of a plausible zero.

Owner question: what is "energy spent controlling the foil"? It has no definition in the code and the actuation model does not exist, so the integrand cannot be written without the owner supplying it — or the owner deciding the port should go.

Test that would prove it

Depends on FISH-0001 and FISH-0004. In tests/in/SimObj-TrawlDoorAddedFoil/, drive FoilRelativeAoa with a Src/SmoothTrajectory so the foil is actively moved against load, and assert FoilEnergyConsumed is monotonically non-decreasing and strictly greater than zero by the end of the run. Today it is flat zero — red before the fix.

Risk

Adding a state changes the state-vector layout for Trawl/TrawlDoorAddedFoil, invalidating any FinalStatesFile written by an older build and any positional assumption about that object's states. No shipped input file uses the type. Ship with FISH-0004.

Why not solved (fix pass 2026-09-15)

Re-confirmed at HEAD: m_foilEnergyConsumed is never accumulated and there is no state behind it, so the FoilEnergyConsumed port is always zero. Fixing it needs a definition of "energy spent controlling the foil" (which integrand, which sign) and, because accumulation requires a state, it changes the state-vector layout of the object. It is also unobservable until FISH-0004 lets the foil force through. Not attempted. Owner decision: define the integrand, or delete the port.