Skip to content

Refresh DfsuModelResult against current mikeio - #707

Open
ecomodeller wants to merge 3 commits into
mainfrom
refresh-dfsu-against-mikeio-3.2
Open

ecomodeller wants to merge 3 commits into
mainfrom
refresh-dfsu-against-mikeio-3.2

Conversation

@ecomodeller

Copy link
Copy Markdown
Member

DfsuModelResult carried workarounds for mikeio behaviour that has since changed, held in place by a mikeio >= 1.2 floor far below what the code actually targets. This raises the floor to 3.2 and drops what it was spanning.

Changes

pyproject.tomlmikeio >= 1.2mikeio >= 3.2. This is the enabling change; ds.z does not exist below 3.2. Note this is a breaking change for installs, not just a cleanup — worth a release note. Timing is good while we are on 1.4.0a3.

Public z accessor (dfsu.py:207). ds_column.geometry.calc_ze(ds_column._zn)ds_column.z.elements. _zn is a private property (mikeio/dataset/_dataset.py:338); the public accessor landed in mikeio 3.2.0 (DHI/mikeio#977). Verified equivalent: np.allclose(ds.z.elements, ds.geometry.calc_ze(ds._zn)) is True.

Also renames layer_boundarieselement_depths. calc_ze documents its return as "Z-coordinates at element centers", not boundaries, and the assertion in test_vertical.py already called them element_depths_expected.

Drop the Dfsu3D read workaround (dfsu.py:196). The FIXME read the full 3D field and selected the column afterwards. read(elements=elemids, items=...) now works directly — on oresund_sigma_z.dfsu both paths return GeometryFMVerticalColumn (3, 5) with identical values and identical calc_ze. Side effect: elemids is load-bearing again. It was computed at :181 and checked for emptiness at :182-183, then never used.

Replace inspect.signature introspection (dfsu.py:261) with hasattr(self.data.geometry, "n_layers"), matching the idiom already used at dfsu.py:187-190. import inspect drops out.

An isinstance(geometry, GeometryFM3D) check would have been wrong here: GeometryFMVerticalProfile is a sibling of GeometryFM3D under _GeometryFMLayered, not a subclass, but its find_index does accept z. The n_layers check separates layered from 2D correctly — GeometryFM2DFalse; GeometryFM3D, GeometryFMVerticalColumn, GeometryFMVerticalProfileTrue — and stays on public API.

Deliberately unchanged

  • np.sort(elemids) (dfsu.py:279-281) stays. find_nearest_elements genuinely returns distance-ordered results ([2850 2451 2851 2142 2485] on Oresund2D.dfsu), so the guard is doing real work rather than spanning old mikeio versions, despite the comment.
  • The Longitude/Latitude vs x/y sniffing (dfsu.py:357-359) stays. extract_track names those columns by projection — a UTM-33 file returns ['x', 'y', 'Surface elevation'] — so the branch is still needed.
  • The Dfsu2DH/Dfsu3D vs Dataset branching throughout. Dfsu3D exposes only read, Dfsu2DH adds extract_track, while Dataset has sel/isel/interp/extract_track. Closing that asymmetry is a mikeio-side change, out of scope here.

Testing

737 passed, 60 skipped on the full suite. mypy clean on dfsu.py. The vertical path is covered by tests/model/test_vertical.py against tests/testdata/oresund_sigma_z.dfsu; that test now asserts against dfsu_col.z.elements rather than the private attribute.

🤖 Generated with Claude Code

ecomodeller and others added 3 commits September 13, 2026 15:12
The dfsu adapter carried workarounds for mikeio behaviour that has since
changed, held in place by a `mikeio >= 1.2` floor far below what the code
actually targets. Raise the floor to 3.2 and drop what it was spanning.

- Use the public `ds.z.elements` accessor (mikeio 3.2, DHI/mikeio#977)
  instead of `geometry.calc_ze(ds._zn)`, which reached into a private
  attribute. Rename `layer_boundaries` to `element_depths`: `calc_ze`
  returns z at element centers, as the assertion in test_vertical.py
  already assumed.
- Read the column directly with `read(elements=elemids)` on Dfsu3D. The
  FIXME workaround read the full 3D field and selected afterwards; the
  direct read now returns identical values and z-coordinates. This also
  makes `elemids` load-bearing again - it was computed and checked for
  emptiness but otherwise unused.
- Replace runtime `inspect.signature` introspection of `find_index` with
  a `n_layers` check. Only layered geometries accept a z argument, and
  this matches the idiom used a few lines above. Note that
  GeometryFMVerticalProfile is not a GeometryFM3D subclass but does take
  z, so an isinstance check against GeometryFM3D would lose z-indexing
  for it.

The `np.sort(elemids)` guard stays: find_nearest_elements returns
distance-ordered results, so it is doing real work rather than spanning
old mikeio versions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Last read by the legacy Python 3.8 CI job, removed in bee6a58
(2024-10-23). Nothing in the tree has referenced it since, and it
never listed mikeio, so it was not a second place to track the
dependency floor.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A dfsu file takes the Dfsu3D read(elements=...) branch; a Dataset takes
sel(x, y). Only the latter had value-level assertions -- the two tests
reaching the Dfsu3D branch check n_points and names, so a regression in
that read would not fail CI.

Assert the two branches agree on z and values, and that both match the
dfsu column read directly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant