Skip to content

reach.length is 100x slower on EPANET res1d files - likely a mikeio1d exception path #684

Description

@jpalm3r

Follow-up from #679.

Res1DReach.__init__ reads reach.length, which goes to mikeio1d's
result_reach.py:_get_total_length. A test user profiled it at ~2.4 s over 8,377 calls on an
EPANET-backed file — ~286 µs per call. On tests/testdata/network.res1d, a MIKE urban model, the
same property costs 2.6 µs. A 100x gap.

The mikeio1d source is:

def _get_total_length(self) -> float:
    total_length = 0
    try:
        for reach in self.reaches:
            total_length += reach.Length
        return total_length
    except Exception as _:
        return total_length

The docstring says it returns zero when no length is available. So the likely explanation is that
Length is unavailable on EPANET links, every call raises, and the cost is exception handling
across the pythonnet boundary — which would also mean every reach gets length 0 and the graph edge
lengths are meaningless on those files.

Next step: confirm what reach.length returns on an EPANET link. If it is 0, this belongs upstream
in mikeio1d rather than worked around in modelskill. Deriving length from
end_chainage - start_chainage is tempting but untested and may hit the same path.

Topology reuse (#682) would avoid the cost in the calibration-loop case regardless, since the reach
loop never runs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions