From dedd694d757cc69cede6b61ba3745bb0e9055479 Mon Sep 17 00:00:00 2001 From: Adrien Morison Date: Sun, 7 Jun 2026 10:34:00 +0100 Subject: [PATCH 01/13] `sdat.filename`: rm unused `suffix` parameter --- src/stagpy/stagyydata.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/stagpy/stagyydata.py b/src/stagpy/stagyydata.py index 889adcb..24c0a73 100644 --- a/src/stagpy/stagyydata.py +++ b/src/stagpy/stagyydata.py @@ -771,7 +771,6 @@ def filename( self, fname: str, timestep: int | None = None, - suffix: str = "", force_legacy: bool = False, ) -> Path: """Return name of StagYY output file. @@ -787,7 +786,6 @@ def filename( """ if timestep is not None: fname += f"{timestep:05d}" - fname += suffix if not force_legacy and self.hdf5: fpath = self.par.h5_output(fname) else: From db18174bf92ad95751ee630621299b71040dea97 Mon Sep 17 00:00:00 2001 From: Adrien Morison Date: Sun, 7 Jun 2026 11:04:48 +0100 Subject: [PATCH 02/13] use `par.h5_output` instead of `filename` where relevant --- src/stagpy/stagyydata.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/stagpy/stagyydata.py b/src/stagpy/stagyydata.py index 24c0a73..b4f5053 100644 --- a/src/stagpy/stagyydata.py +++ b/src/stagpy/stagyydata.py @@ -147,7 +147,8 @@ def _cached_extra(self) -> dict[str, dt.Tseries]: @cached_property def _data(self) -> DataFrame | None: - timefile = self.sdat.filename("TimeSeries.h5") + timefile: Path | None + timefile = self.sdat.par.h5_output("TimeSeries.h5") data = parsers.h5.tseries.tseries(timefile) if data is not None: return data @@ -732,7 +733,8 @@ def par(self) -> StagyyPar: @cached_property def _rprof_and_times(self) -> tuple[dict[int, DataFrame], DataFrame | None]: - rproffile = self.filename("rprof.h5") + rproffile: Path | None + rproffile = self.par.h5_output("rprof.h5") data = parsers.h5.rprof.rprof(rproffile) if data[1] is not None: return data From 9345511f2adef95ab1b048882d64a17bced3978b Mon Sep 17 00:00:00 2001 From: Adrien Morison Date: Sun, 7 Jun 2026 11:08:28 +0100 Subject: [PATCH 03/13] par.legacy_output formats properly a legacy output file It is used instead of `filename` where relevant --- src/stagpy/_caching.py | 2 +- src/stagpy/parfile.py | 8 +++++--- src/stagpy/stagyydata.py | 7 +++---- src/stagpy/step.py | 9 +++------ 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/stagpy/_caching.py b/src/stagpy/_caching.py index b2a7c33..95b504c 100644 --- a/src/stagpy/_caching.py +++ b/src/stagpy/_caching.py @@ -131,7 +131,7 @@ def _snap_to_step(self) -> dict[int, int | None]: @cached_property def isnap_max(self) -> int: imax = -1 - out_stem = re.escape(self.sdat.par.legacy_output("_").name[:-1]) + out_stem = re.escape(self.sdat.par.legacy_output("").name[:-1]) rgx = re.compile(f"^{out_stem}_([a-zA-Z]+)([0-9]{{5}})$") fstems = set(fstem for fstem in phyvars.FIELD_FILES) for fname in self.sdat._files: diff --git a/src/stagpy/parfile.py b/src/stagpy/parfile.py index 2370bed..622121c 100644 --- a/src/stagpy/parfile.py +++ b/src/stagpy/parfile.py @@ -68,7 +68,7 @@ def from_main_par(parfile: Path, read_parameters_dat: bool = True) -> StagyyPar: par_main = StagyyPar(nml=par_dflt.nml, root=par_main.root) if read_parameters_dat: - outfile = par_main.legacy_output("_parameters.dat") + outfile = par_main.legacy_output("parameters.dat") if outfile.is_file(): par_main._update(StagyyPar._from_file(outfile)) outfile = par_main.h5_output("parameters.dat") @@ -80,9 +80,11 @@ def get(self, section: str, option: str, default: T) -> T: sec = self.nml.get(section, {}) return sec.get(option, default) - def legacy_output(self, suffix: str) -> Path: + def legacy_output(self, suffix: str, isnap: int | None = None) -> Path: + if isnap is not None: + suffix += f"{isnap:05d}" stem = self.get("ioin", "output_file_stem", "output") - return self.root / (stem + suffix) + return self.root / f"{stem}_{suffix}" def h5_output(self, filename: str) -> Path: h5folder = self.get("ioin", "hdf5_output_folder", "+hdf5") diff --git a/src/stagpy/stagyydata.py b/src/stagpy/stagyydata.py index b4f5053..a994cab 100644 --- a/src/stagpy/stagyydata.py +++ b/src/stagpy/stagyydata.py @@ -752,7 +752,7 @@ def rtimes(self) -> DataFrame | None: @cached_property def _files(self) -> set[Path]: """Set of found binary files output by StagYY.""" - out_dir = self.par.legacy_output("_").parent + out_dir = self.par.legacy_output("").parent if out_dir.is_dir(): return set(out_dir.iterdir()) return set() @@ -791,7 +791,7 @@ def filename( if not force_legacy and self.hdf5: fpath = self.par.h5_output(fname) else: - fpath = self.par.legacy_output(f"_{fname}") + fpath = self.par.legacy_output(fname) return fpath def _binfiles_set(self, isnap: int) -> set[Path]: @@ -804,8 +804,7 @@ def _binfiles_set(self, isnap: int) -> set[Path]: the set of output files available for this snapshot number. """ possible_files = set( - self.filename(fstem, isnap, force_legacy=True) - for fstem in phyvars.FIELD_FILES + self.par.legacy_output(fstem, isnap) for fstem in phyvars.FIELD_FILES ) return possible_files & self._files diff --git a/src/stagpy/step.py b/src/stagpy/step.py index fbbef37..7688065 100644 --- a/src/stagpy/step.py +++ b/src/stagpy/step.py @@ -352,11 +352,7 @@ def _get_raw_data(self, name: str) -> tuple[list[str], Any]: parsed_data = None if self.step.isnap is None: return list_fvar, None - fieldfile = self.step.sdat.filename( - filestem, self.step.isnap, force_legacy=True - ) - if not fieldfile.is_file(): - fieldfile = self.step.sdat.filename(filestem, self.step.isnap) + fieldfile = self.step.sdat.par.legacy_output(filestem, self.step.isnap) if fieldfile.is_file(): parsed_data = parsers.bin.field.field(fieldfile) elif self.step.sdat.hdf5 and self.filesh5: @@ -403,8 +399,9 @@ def __getitem__(self, name: str) -> list[NDArray[np.floating]] | None: return self._data[name] if self.step.isnap is None: return None + sdat = self.step.sdat data = parsers.bin.tracers.tracers( - self.step.sdat.filename("tra", timestep=self.step.isnap, force_legacy=True) + sdat.par.legacy_output("tra", self.step.isnap) ) if data is None and self.step.sdat.hdf5: self._data[name] = parsers.h5.tracers.tracers( # type: ignore From b193d44353cd565ad7c3bc12a558e7a674dd9859 Mon Sep 17 00:00:00 2001 From: Adrien Morison Date: Sun, 7 Jun 2026 11:16:09 +0100 Subject: [PATCH 04/13] new `sdat._find_file` for files that can be in h5 or legacy --- src/stagpy/stagyydata.py | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/stagpy/stagyydata.py b/src/stagpy/stagyydata.py index a994cab..ecff8f6 100644 --- a/src/stagpy/stagyydata.py +++ b/src/stagpy/stagyydata.py @@ -78,11 +78,10 @@ class Refstate: @cached_property def _data(self) -> tuple[list[list[DataFrame]], list[DataFrame]]: """Read reference state profile.""" - reffile = self.sdat.filename("refstat.dat") - if self.sdat.hdf5 and not reffile.is_file(): - # check legacy folder as well - reffile = self.sdat.filename("refstat.dat", force_legacy=True) - data = parsers.txt.refstate(reffile) + reffile = self.sdat._find_file("refstat.dat") + data = None + if reffile is not None: + data = parsers.txt.refstate(reffile) if data is None: raise error.NoRefstateError(self.sdat) return data @@ -152,11 +151,9 @@ def _data(self) -> DataFrame | None: data = parsers.h5.tseries.tseries(timefile) if data is not None: return data - timefile = self.sdat.filename("time.dat") - if self.sdat.hdf5 and not timefile.is_file(): - # check legacy folder as well - timefile = self.sdat.filename("time.dat", force_legacy=True) - data = parsers.txt.tseries(timefile) + timefile = self.sdat._find_file("time.dat") + if timefile is not None: + data = parsers.txt.tseries(timefile) return data @property @@ -738,11 +735,10 @@ def _rprof_and_times(self) -> tuple[dict[int, DataFrame], DataFrame | None]: data = parsers.h5.rprof.rprof(rproffile) if data[1] is not None: return data - rproffile = self.filename("rprof.dat") - if self.hdf5 and not rproffile.is_file(): - # check legacy folder as well - rproffile = self.filename("rprof.dat", force_legacy=True) - return parsers.txt.rprof(rproffile) + rproffile = self._find_file("rprof.dat") + if rproffile is not None: + return parsers.txt.rprof(rproffile) + return {}, None @property def rtimes(self) -> DataFrame | None: @@ -769,6 +765,20 @@ def set_nfields_max(self, nfields: int | None) -> None: raise error.InvalidNfieldsError(nfields) self._field_cache.resize(nfields) + def _find_file(self, fname: str) -> Path | None: + """Return path of StagYY output file if found. + + This searches in the legacy folder first, and then the hdf5 + output folder. + """ + fpath = self.par.legacy_output(fname) + if fpath.is_file(): + return fpath + fpath = self.par.h5_output(fname) + if fpath.is_file(): + return fpath + return None + def filename( self, fname: str, From 14a973d14c87f2f3ce5e43b1b17d715f132e4162 Mon Sep 17 00:00:00 2001 From: Adrien Morison Date: Sun, 7 Jun 2026 19:03:43 +0100 Subject: [PATCH 05/13] tests: use `par.legacy_output` instead of `sdat.filename` --- tests/test_parsers.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_parsers.py b/tests/test_parsers.py index c882e80..cb0ee73 100644 --- a/tests/test_parsers.py +++ b/tests/test_parsers.py @@ -6,7 +6,7 @@ def test_time_series_prs(sdat_legacy: StagyyData) -> None: sdat = sdat_legacy - data = parsers.txt.tseries(sdat.filename("time.dat")) + data = parsers.txt.tseries(sdat.par.legacy_output("time.dat")) assert data is not None assert (data.columns[3:6] == ["Tmin", "Tmean", "Tmax"]).all() @@ -25,7 +25,7 @@ def test_time_series_invalid_prs() -> None: def test_rprof_prs(sdat_legacy: StagyyData) -> None: sdat = sdat_legacy - data, _time = parsers.txt.rprof(sdat.filename("rprof.dat")) + data, _time = parsers.txt.rprof(sdat.par.legacy_output("rprof.dat")) assert all((df.columns[:3] == ["r", "Tmean", "Tmin"]).all() for df in data.values()) @@ -43,7 +43,7 @@ def test_rprof_invalid_prs() -> None: def test_fields_prs(sdat_legacy: StagyyData) -> None: sdat = sdat_legacy - parsed = parsers.bin.field.field(sdat.filename("t", len(sdat.snaps) - 1)) + parsed = parsers.bin.field.field(sdat.par.legacy_output("t", len(sdat.snaps) - 1)) assert parsed is not None hdr, flds = parsed assert flds.shape[0] == 1 @@ -53,14 +53,14 @@ def test_fields_prs(sdat_legacy: StagyyData) -> None: def test_field_header_prs(sdat_legacy: StagyyData) -> None: sdat = sdat_legacy - hdr = parsers.bin.field.header(sdat.filename("t", len(sdat.snaps) - 1)) + hdr = parsers.bin.field.header(sdat.par.legacy_output("t", len(sdat.snaps) - 1)) assert hdr is not None assert hdr["nts"].shape == (3,) def test_fields_istep_prs(sdat_legacy: StagyyData) -> None: sdat = sdat_legacy - istep = parsers.bin.field.istep(sdat.filename("t", len(sdat.snaps) - 1)) + istep = parsers.bin.field.istep(sdat.par.legacy_output("t", len(sdat.snaps) - 1)) assert istep == sdat.snaps[-1].istep From 0ce2a6128cc9a792400c16a7d2aa0407555c7fb3 Mon Sep 17 00:00:00 2001 From: Adrien Morison Date: Sun, 7 Jun 2026 19:04:59 +0100 Subject: [PATCH 06/13] rm unused `sdat.filename` --- src/stagpy/stagyydata.py | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/stagpy/stagyydata.py b/src/stagpy/stagyydata.py index ecff8f6..9c3c60c 100644 --- a/src/stagpy/stagyydata.py +++ b/src/stagpy/stagyydata.py @@ -779,31 +779,6 @@ def _find_file(self, fname: str) -> Path | None: return fpath return None - def filename( - self, - fname: str, - timestep: int | None = None, - force_legacy: bool = False, - ) -> Path: - """Return name of StagYY output file. - - Args: - fname: name stem. - timestep: snapshot number if relevant. - suffix: optional suffix of file name. - force_legacy: force returning the legacy output path. - - Returns: - the path of the output file constructed with the provided segments. - """ - if timestep is not None: - fname += f"{timestep:05d}" - if not force_legacy and self.hdf5: - fpath = self.par.h5_output(fname) - else: - fpath = self.par.legacy_output(fname) - return fpath - def _binfiles_set(self, isnap: int) -> set[Path]: """Set of existing binary files at a given snap. From d42f4f35d67f488fec41228ec329aaf9e28fd4bd Mon Sep 17 00:00:00 2001 From: Adrien Morison Date: Sun, 7 Jun 2026 19:10:31 +0100 Subject: [PATCH 07/13] `isnap_istep` parser takes a filepath --- src/stagpy/_caching.py | 4 ++-- src/stagpy/parsers/h5/extras.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/stagpy/_caching.py b/src/stagpy/_caching.py index 95b504c..6f036c7 100644 --- a/src/stagpy/_caching.py +++ b/src/stagpy/_caching.py @@ -93,11 +93,11 @@ class StepSnapH5(StepSnap): @cached_property def _info(self) -> StepSnapInfo: - assert self.sdat.hdf5 is not None isnap = -1 step_to_snap = {} snap_to_step = {} - for isnap, istep in parsers.h5.extras.isnap_istep(self.sdat.hdf5): + timeh5 = self.sdat.par.h5_output("time_botT.h5") + for isnap, istep in parsers.h5.extras.isnap_istep(timeh5): step_to_snap[istep] = isnap snap_to_step[isnap] = istep return StepSnapInfo( diff --git a/src/stagpy/parsers/h5/extras.py b/src/stagpy/parsers/h5/extras.py index fa047ba..8a571c1 100644 --- a/src/stagpy/parsers/h5/extras.py +++ b/src/stagpy/parsers/h5/extras.py @@ -9,16 +9,16 @@ from pathlib import Path -def isnap_istep(h5folder: Path) -> Iterator[tuple[int, int]]: - """Iterate through (isnap, istep) recorded in h5folder/'time_botT.h5'. +def isnap_istep(timeh5: Path) -> Iterator[tuple[int, int]]: + """Iterate through (isnap, istep) recorded in 'time_botT.h5'. Args: - h5folder: directory of HDF5 output files. + timeh5: path of the time h5 file. Yields: tuple (isnap, istep). """ - with h5py.File(h5folder / "time_botT.h5", "r") as h5f: + with h5py.File(timeh5, "r") as h5f: for name, dset in h5f.items(): isnap = int(name[-5:]) if len(dset) == 3: From 74dbb5740cf5dd05e81d8c982648bc4d17db7ba2 Mon Sep 17 00:00:00 2001 From: Adrien Morison Date: Sun, 7 Jun 2026 19:15:02 +0100 Subject: [PATCH 08/13] test_parsers: use `par.h5_output` instead of `sdat.hdf5` --- tests/test_parsers.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/test_parsers.py b/tests/test_parsers.py index cb0ee73..9669914 100644 --- a/tests/test_parsers.py +++ b/tests/test_parsers.py @@ -12,9 +12,8 @@ def test_time_series_prs(sdat_legacy: StagyyData) -> None: def test_time_series_h5(sdat_h5: StagyyData) -> None: - sdat = sdat_h5 - assert sdat.hdf5 is not None - data = parsers.h5.tseries.tseries(sdat.hdf5 / "TimeSeries.h5") + path = sdat_h5.par.h5_output("TimeSeries.h5") + data = parsers.h5.tseries.tseries(path) assert data is not None assert (data.columns[3:6] == ["Tmin", "Tmean", "Tmax"]).all() @@ -30,9 +29,8 @@ def test_rprof_prs(sdat_legacy: StagyyData) -> None: def test_rprof_h5(sdat_h5: StagyyData) -> None: - sdat = sdat_h5 - assert sdat.hdf5 is not None - data, _times = parsers.h5.rprof.rprof(sdat.hdf5 / "rprof.h5") + path = sdat_h5.par.h5_output("rprof.h5") + data, _times = parsers.h5.rprof.rprof(path) assert data is not None assert (data[1000].columns[:3] == ["r", "Tmean", "Tmin"]).all() From e160d62b65ffc48bb5de9bb2efc1263d3184b0c4 Mon Sep 17 00:00:00 2001 From: Adrien Morison Date: Sun, 7 Jun 2026 19:41:06 +0100 Subject: [PATCH 09/13] only build `_traxmf` if xmf exists --- src/stagpy/stagyydata.py | 10 +++++----- src/stagpy/step.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/stagpy/stagyydata.py b/src/stagpy/stagyydata.py index 9c3c60c..1094e65 100644 --- a/src/stagpy/stagyydata.py +++ b/src/stagpy/stagyydata.py @@ -717,11 +717,11 @@ def _botxmf(self) -> FieldXmf: ) @cached_property - def _traxmf(self) -> TracersXmf: - assert self.hdf5 is not None - return TracersXmf( - path=self.hdf5 / "DataTracers.xmf", - ) + def _traxmf(self) -> TracersXmf | None: + path = self.par.h5_output("DataTracers.xmf") + if path.is_file(): + return TracersXmf(path=path) + return None @cached_property def par(self) -> StagyyPar: diff --git a/src/stagpy/step.py b/src/stagpy/step.py index 7688065..310f520 100644 --- a/src/stagpy/step.py +++ b/src/stagpy/step.py @@ -403,9 +403,9 @@ def __getitem__(self, name: str) -> list[NDArray[np.floating]] | None: data = parsers.bin.tracers.tracers( sdat.par.legacy_output("tra", self.step.isnap) ) - if data is None and self.step.sdat.hdf5: + if data is None and sdat._traxmf is not None: self._data[name] = parsers.h5.tracers.tracers( # type: ignore - self.step.sdat._traxmf, + sdat._traxmf, name, self.step.isnap, ) From 55bd444a39a727523df846bb990fdb7743818a28 Mon Sep 17 00:00:00 2001 From: Adrien Morison Date: Sun, 7 Jun 2026 19:51:10 +0100 Subject: [PATCH 10/13] return early in `_get_raw_data` --- src/stagpy/step.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/stagpy/step.py b/src/stagpy/step.py index 310f520..557938e 100644 --- a/src/stagpy/step.py +++ b/src/stagpy/step.py @@ -355,25 +355,25 @@ def _get_raw_data(self, name: str) -> tuple[list[str], Any]: fieldfile = self.step.sdat.par.legacy_output(filestem, self.step.isnap) if fieldfile.is_file(): parsed_data = parsers.bin.field.field(fieldfile) - elif self.step.sdat.hdf5 and self.filesh5: - # files in which the requested data can be found - files = [ - (stem, fvars) for stem, fvars in self.filesh5.items() if name in fvars - ] - for filestem, list_fvar in files: - sdat = self.step.sdat - if filestem in phyvars.SFIELD_FILES_H5: - xmff = sdat._botxmf if name.endswith("bot") else sdat._topxmf - header = self.step.geom._maybe_header - assert header is not None - else: - xmff = sdat._dataxmf - header = None - parsed_data = parsers.h5.field.field( - xmff, filestem, self.step.isnap, header - ) - if parsed_data is not None: - break + return list_fvar, parsed_data + if not (self.step.sdat.hdf5 and self.filesh5): + return list_fvar, parsed_data + # files in which the requested data can be found + files = [(stem, fvars) for stem, fvars in self.filesh5.items() if name in fvars] + for filestem, list_fvar in files: + sdat = self.step.sdat + if filestem in phyvars.SFIELD_FILES_H5: + xmff = sdat._botxmf if name.endswith("bot") else sdat._topxmf + header = self.step.geom._maybe_header + assert header is not None + else: + xmff = sdat._dataxmf + header = None + parsed_data = parsers.h5.field.field( + xmff, filestem, self.step.isnap, header + ) + if parsed_data is not None: + break return list_fvar, parsed_data From df5efebb34f5abb1a304b0abd013c944005d1d29 Mon Sep 17 00:00:00 2001 From: Adrien Morison Date: Sun, 7 Jun 2026 20:06:38 +0100 Subject: [PATCH 11/13] only build `_*xmf` if relevant file exists --- src/stagpy/stagyydata.py | 30 +++++++++++++++--------------- src/stagpy/step.py | 14 +++++++++----- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/stagpy/stagyydata.py b/src/stagpy/stagyydata.py index 1094e65..2b4c4a2 100644 --- a/src/stagpy/stagyydata.py +++ b/src/stagpy/stagyydata.py @@ -696,25 +696,25 @@ def refstate(self) -> Refstate: return Refstate(self) @cached_property - def _dataxmf(self) -> FieldXmf: - assert self.hdf5 is not None - return FieldXmf( - path=self.hdf5 / "Data.xmf", - ) + def _dataxmf(self) -> FieldXmf | None: + path = self.par.h5_output("Data.xmf") + if path.is_file(): + return FieldXmf(path=path) + return None @cached_property - def _topxmf(self) -> FieldXmf: - assert self.hdf5 is not None - return FieldXmf( - path=self.hdf5 / "DataSurface.xmf", - ) + def _topxmf(self) -> FieldXmf | None: + path = self.par.h5_output("DataSurface.xmf") + if path.is_file(): + return FieldXmf(path=path) + return None @cached_property - def _botxmf(self) -> FieldXmf: - assert self.hdf5 is not None - return FieldXmf( - path=self.hdf5 / "DataBottom.xmf", - ) + def _botxmf(self) -> FieldXmf | None: + path = self.par.h5_output("DataBottom.xmf") + if path.is_file(): + return FieldXmf(path=path) + return None @cached_property def _traxmf(self) -> TracersXmf | None: diff --git a/src/stagpy/step.py b/src/stagpy/step.py index 557938e..1433c9f 100644 --- a/src/stagpy/step.py +++ b/src/stagpy/step.py @@ -50,7 +50,7 @@ def _maybe_header(self) -> dict[str, Any] | None: header = None if binfiles: header = parsers.bin.field.header(binfiles.pop()) - elif sdat.hdf5: + elif sdat._dataxmf is not None: header = parsers.h5.field.read_geom(sdat._dataxmf, self.step.isnap) return header if header else None @@ -356,18 +356,22 @@ def _get_raw_data(self, name: str) -> tuple[list[str], Any]: if fieldfile.is_file(): parsed_data = parsers.bin.field.field(fieldfile) return list_fvar, parsed_data - if not (self.step.sdat.hdf5 and self.filesh5): + if not self.filesh5: return list_fvar, parsed_data # files in which the requested data can be found files = [(stem, fvars) for stem, fvars in self.filesh5.items() if name in fvars] + sdat = self.step.sdat + if filestem in phyvars.SFIELD_FILES_H5: + xmff = sdat._botxmf if name.endswith("bot") else sdat._topxmf + else: + xmff = sdat._dataxmf + if xmff is None: + return list_fvar, parsed_data for filestem, list_fvar in files: - sdat = self.step.sdat if filestem in phyvars.SFIELD_FILES_H5: - xmff = sdat._botxmf if name.endswith("bot") else sdat._topxmf header = self.step.geom._maybe_header assert header is not None else: - xmff = sdat._dataxmf header = None parsed_data = parsers.h5.field.field( xmff, filestem, self.step.isnap, header From 0c0a0d54c695d434be14ae25c7a35f70ad147840 Mon Sep 17 00:00:00 2001 From: Adrien Morison Date: Sun, 7 Jun 2026 20:17:57 +0100 Subject: [PATCH 12/13] StepSnapH5 only built if timeh5 exists StepSnapH5 also now directly holds the path to timeh5 instead of the entire `sdat` instance. --- src/stagpy/_caching.py | 6 +++--- src/stagpy/stagyydata.py | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/stagpy/_caching.py b/src/stagpy/_caching.py index 6f036c7..01a41f0 100644 --- a/src/stagpy/_caching.py +++ b/src/stagpy/_caching.py @@ -12,6 +12,7 @@ if typing.TYPE_CHECKING: from collections.abc import Mapping + from pathlib import Path from .datatypes import Field from .stagyydata import StagyyData @@ -89,15 +90,14 @@ class StepSnapInfo: @dataclass(frozen=True) class StepSnapH5(StepSnap): - sdat: StagyyData + timeh5: Path @cached_property def _info(self) -> StepSnapInfo: isnap = -1 step_to_snap = {} snap_to_step = {} - timeh5 = self.sdat.par.h5_output("time_botT.h5") - for isnap, istep in parsers.h5.extras.isnap_istep(timeh5): + for isnap, istep in parsers.h5.extras.isnap_istep(self.timeh5): step_to_snap[istep] = isnap snap_to_step[isnap] = istep return StepSnapInfo( diff --git a/src/stagpy/stagyydata.py b/src/stagpy/stagyydata.py index 2b4c4a2..dc353b9 100644 --- a/src/stagpy/stagyydata.py +++ b/src/stagpy/stagyydata.py @@ -799,6 +799,7 @@ def _field_cache(self) -> FieldCache: @cached_property def _step_snap(self) -> StepSnap: - if self.hdf5 is not None: - return StepSnapH5(sdat=self) + timeh5 = self.par.h5_output("time_botT.h5") + if timeh5.is_file(): + return StepSnapH5(timeh5=timeh5) return StepSnapLegacy(sdat=self) From d3e5444f92fedb9f7861afd32a430356be40f003 Mon Sep 17 00:00:00 2001 From: Adrien Morison Date: Sun, 7 Jun 2026 20:19:44 +0100 Subject: [PATCH 13/13] rm unused `sdat.hdf5` property --- src/stagpy/stagyydata.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/stagpy/stagyydata.py b/src/stagpy/stagyydata.py index dc353b9..fec7673 100644 --- a/src/stagpy/stagyydata.py +++ b/src/stagpy/stagyydata.py @@ -669,12 +669,6 @@ def parpath(self) -> Path: return parpath return parpath / "par" - @cached_property - def hdf5(self) -> Path | None: - """Path of output hdf5 folder if relevant, None otherwise.""" - h5xmf = self.par.h5_output("Data.xmf") - return h5xmf.parent if h5xmf.is_file() else None - @cached_property def steps(self) -> Steps: """Collection of time steps."""