lisainstrument 2.0.0b4__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/PKG-INFO +7 -6
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/README.md +2 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/__init__.py +1 -2
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/instru/__init__.py +1 -1
- lisainstrument-2.2.0/lisainstrument/instru/instru_file_reader.py +468 -0
- lisainstrument-2.0.0b4/lisainstrument/instru/instru_file_reader.py → lisainstrument-2.2.0/lisainstrument/instru/instru_file_reader_v2_0_0.py +75 -20
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/instru/instru_formulas.py +19 -4
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/instru/instru_model.py +25 -4
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/instru/instru_noises.py +11 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/instru/instru_orbsrc.py +12 -3
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/instru/instru_store.py +8 -0
- lisainstrument-2.2.0/lisainstrument/instru/instru_store_v2_0_0.py +936 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/instrument.py +40 -24
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/legacy/containers.py +0 -2
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/legacy/dsp.py +0 -2
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/legacy/hexagon.py +0 -2
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/legacy/noises.py +0 -2
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/noisy/__init__.py +5 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/noisy/noise_defs.py +212 -25
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/noisy/noise_defs_lisa.py +210 -62
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/noisy/noise_gen_numpy.py +2 -1
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/orbiting/constellation_enums.py +3 -3
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/orbiting/orbit_file.py +34 -15
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/sigpro/fir_filters_numpy.py +1 -1
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/__init__.py +1 -1
- lisainstrument-2.2.0/lisainstrument/streams/analysis.py +417 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/hdf5_store.py +107 -14
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/scheduler.py +1 -1
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/segments.py +23 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/store.py +14 -6
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/pyproject.toml +6 -5
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/LICENSE +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/__main__.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/cli/__init__.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/cli/run_simulation.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/freqplan/__init__.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/freqplan/fplan_file.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/freqplan/fplan_source.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/freqplan/fplan_source_interp.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/glitches/__init__.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/glitches/glitch_file.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/glitches/glitch_source.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/glitches/glitch_source_interp.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/gwsource/__init__.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/gwsource/gw_file.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/gwsource/gw_source.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/gwsource/hdf5util.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/instru/instru_defaults.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/instru/instru_filter.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/instru/instru_fplan.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/instru/instru_glitchsrc.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/instru/instru_gwsrc.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/instru/instru_locking.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/legacy/__init__.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/legacy/dynamic_delay_dsp.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/legacy/fixed_shift_dsp.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/legacy/legacy_plots.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/legacy/pyplnoise/LICENSE +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/legacy/pyplnoise/__init__.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/legacy/pyplnoise/pyplnoise.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/noisy/estimate_psd.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/orbiting/__init__.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/orbiting/orbit_source.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/orbiting/orbit_source_interp.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/sigpro/__init__.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/sigpro/adaptive_delay_numpy.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/sigpro/chunked_splines.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/sigpro/dynamic_delay_numpy.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/sigpro/fixed_shift_numpy.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/sigpro/iir_filters_numpy.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/sigpro/regular_interpolators.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/sigpro/shift_inversion_numpy.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/sigpro/types_numpy.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/array.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/delay.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/derivative.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/expression.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/firfilter.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/graph_util.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/iirfilter.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/integrate.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/noise.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/noise_alt.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/null_store.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/numpy_store.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/sampling.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/scheduler_dask.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/scheduler_serial.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/shift_inv.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/streams.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/streams/time.py +0 -0
- {lisainstrument-2.0.0b4 → lisainstrument-2.2.0}/lisainstrument/version.py +0 -0
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: lisainstrument
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Simulates the LISA measurement chain (noise and signals) and generates telemetry data
|
|
5
5
|
Home-page: https://gitlab.in2p3.fr/lisa-simulation/instrument
|
|
6
6
|
License: BSD 3-Clause
|
|
7
7
|
Author: Jean-Baptiste Bayle
|
|
8
8
|
Author-email: j2b.bayle@gmail.com
|
|
9
|
-
Maintainer:
|
|
10
|
-
Maintainer-email:
|
|
11
|
-
Requires-Python: >=3.
|
|
9
|
+
Maintainer: Wolfgang Kastaun
|
|
10
|
+
Maintainer-email: wolfgang.kastaun@aei.mpg.de
|
|
11
|
+
Requires-Python: >=3.11,<4.0
|
|
12
12
|
Classifier: Intended Audience :: Science/Research
|
|
13
13
|
Classifier: License :: Other/Proprietary License
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
@@ -27,7 +26,7 @@ Requires-Dist: lisaconstants (>=2.0.1,<3.0.0)
|
|
|
27
26
|
Requires-Dist: matplotlib (>=3.9.2,<4.0.0)
|
|
28
27
|
Requires-Dist: numpy (>=2.1.2,<3.0.0)
|
|
29
28
|
Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
|
|
30
|
-
Requires-Dist: scipy (>=1.
|
|
29
|
+
Requires-Dist: scipy (>=1.17.1,<2.0.0)
|
|
31
30
|
Requires-Dist: typing-extensions (>=4.15.0,<5.0.0)
|
|
32
31
|
Project-URL: Documentation, https://lisa-simulation.pages.in2p3.fr/instrument
|
|
33
32
|
Project-URL: Download, https://gitlab.in2p3.fr/lisa-simulation/instrument/-/releases
|
|
@@ -138,4 +137,6 @@ We use a newly created noise generation framework based on the same principles.
|
|
|
138
137
|
For comparison, J. Waldmann's pyplnoise module is still distributed with this
|
|
139
138
|
project as a submodule.
|
|
140
139
|
You can find the original project at <https://github.com/janwaldmann/pyplnoise>.
|
|
140
|
+
We also thank G. Wanner and S. Paczkowski for helpful discussions regarding the TTL
|
|
141
|
+
coupling documentation.
|
|
141
142
|
|
|
@@ -101,3 +101,5 @@ We use a newly created noise generation framework based on the same principles.
|
|
|
101
101
|
For comparison, J. Waldmann's pyplnoise module is still distributed with this
|
|
102
102
|
project as a submodule.
|
|
103
103
|
You can find the original project at <https://github.com/janwaldmann/pyplnoise>.
|
|
104
|
+
We also thank G. Wanner and S. Paczkowski for helpful discussions regarding the TTL
|
|
105
|
+
coupling documentation.
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
"""LISA Instrument module."""
|
|
3
2
|
|
|
4
3
|
from .glitches import glitch_file
|
|
5
4
|
from .gwsource import gw_file
|
|
6
|
-
from .instru import SimResultFile
|
|
5
|
+
from .instru import SimResultFile, sim_result_file
|
|
7
6
|
from .instrument import Instrument
|
|
8
7
|
from .orbiting import MosaID, SatID, orbit_file
|
|
9
8
|
from .streams import SchedulerConfigParallel, SchedulerConfigSerial
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Those are not for general use but more specific to the Instrument class.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from lisainstrument.instru.instru_file_reader import SimResultFile
|
|
6
|
+
from lisainstrument.instru.instru_file_reader import SimResultFile, sim_result_file
|
|
7
7
|
from lisainstrument.instru.instru_filter import InstruDelays, init_aafilter
|
|
8
8
|
from lisainstrument.instru.instru_fplan import init_fplan_source
|
|
9
9
|
from lisainstrument.instru.instru_glitchsrc import init_glitch_source
|
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
"""The instru.instru_file_reader module allows reading data from simulation result files.
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
This module is not required by the simulator but supports using simulation
|
|
5
|
+
results in post-processing. The SimResultFile is a low-level representation of
|
|
6
|
+
a simulation result file, allowing direct access to datasets without having to
|
|
7
|
+
know the internal file format. It also provides a view of the simulation data
|
|
8
|
+
as a StreamBundle, allowing chunked processing of saved simulation results.
|
|
9
|
+
Besides chunked processing, it also allows reading all data into memory at once,
|
|
10
|
+
collected in a SimResultsNumpyCore or SimResultsNumpyFull instance.
|
|
11
|
+
|
|
12
|
+
For reading back instrument result files, one should normally use the function
|
|
13
|
+
`lisainstrument.instru.sim_result_file` since it additionally supports loading
|
|
14
|
+
file formats created by previous versions.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import pathlib
|
|
19
|
+
from collections import defaultdict
|
|
20
|
+
from typing import Final, TypeVar
|
|
21
|
+
|
|
22
|
+
import h5py
|
|
23
|
+
import numpy as np
|
|
24
|
+
from packaging.specifiers import SpecifierSet
|
|
25
|
+
from packaging.version import Version
|
|
26
|
+
|
|
27
|
+
from lisainstrument.instru.instru_file_reader_v2_0_0 import (
|
|
28
|
+
SimResultFile as SimResultFile_V2_0_0,
|
|
29
|
+
)
|
|
30
|
+
from lisainstrument.instru.instru_store import (
|
|
31
|
+
IdxSpace,
|
|
32
|
+
SimFullDatasetsMOSA,
|
|
33
|
+
SimFullDatasetsSat,
|
|
34
|
+
SimMetaData,
|
|
35
|
+
SimResultsNumpyCore,
|
|
36
|
+
SimResultsNumpyFull,
|
|
37
|
+
datasets_metadata_dict,
|
|
38
|
+
make_dataset_id,
|
|
39
|
+
)
|
|
40
|
+
from lisainstrument.orbiting.constellation_enums import MosaID, SatID
|
|
41
|
+
from lisainstrument.streams import DatasetIdentifier, StreamBundle
|
|
42
|
+
from lisainstrument.streams.hdf5_store import (
|
|
43
|
+
DataStorageHDF5,
|
|
44
|
+
instru_hdf5_file_as_stream_bundle,
|
|
45
|
+
)
|
|
46
|
+
from lisainstrument.streams.numpy_store import store_bundle_numpy
|
|
47
|
+
from lisainstrument.version import __version__
|
|
48
|
+
|
|
49
|
+
_T = TypeVar("_T", SimResultsNumpyFull, SimResultsNumpyCore)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _unique_index_range(ranges: list[tuple[int, int]]) -> tuple[int, int]:
|
|
53
|
+
"""Ensure index ranges in list are identical and return that range"""
|
|
54
|
+
s = set(ranges)
|
|
55
|
+
if len(s) != 1:
|
|
56
|
+
msg = f"unique_index_range: ranges not identical ({ranges=})"
|
|
57
|
+
raise RuntimeError(msg)
|
|
58
|
+
(uni,) = list(s)
|
|
59
|
+
return uni
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class SimResultFile:
|
|
63
|
+
"""Represents a simulation result file in HDF5 format.
|
|
64
|
+
|
|
65
|
+
There are low-level methods for direct reading of datasets identified either
|
|
66
|
+
by name and MOSA or SC index, or by a DatasetIdentifier. For use cases where the
|
|
67
|
+
results fit into memory, there are methods to create a SimResultsNumpyCore or
|
|
68
|
+
SimResultsNumpyFull instance with the data and metadata.
|
|
69
|
+
|
|
70
|
+
For use cases dealing with large data sets, there is a method representing
|
|
71
|
+
the datasets as streams in a StreamBundle for use with chunked processing.
|
|
72
|
+
For all those methods, it is possible to restrict the data to a given time
|
|
73
|
+
interval.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
def __init__(self, path: pathlib.Path | str):
|
|
77
|
+
"""Constructor
|
|
78
|
+
|
|
79
|
+
Arguments:
|
|
80
|
+
path: Path of the a HDF5 file created by store_instru_hdf5
|
|
81
|
+
"""
|
|
82
|
+
self._h5f_raw = h5py.File(str(path), "r")
|
|
83
|
+
self._version: Final = Version(self._h5f.attrs["version_format"])
|
|
84
|
+
|
|
85
|
+
if not SimResultFile.format_specifier().contains(self._version):
|
|
86
|
+
msg = f"File {path} version {self._version} not compatible with file reader"
|
|
87
|
+
raise RuntimeError(msg)
|
|
88
|
+
|
|
89
|
+
ds_actual = set(self._h5f.keys()) - {"debug"}
|
|
90
|
+
ds_debug = set(self._h5f["debug"].keys())
|
|
91
|
+
ds_all = ds_actual | ds_debug
|
|
92
|
+
|
|
93
|
+
if ds_all == SimResultsNumpyFull.all_dataset_names:
|
|
94
|
+
self._extended = True
|
|
95
|
+
elif ds_all == SimResultsNumpyCore.all_dataset_names:
|
|
96
|
+
self._extended = False
|
|
97
|
+
else:
|
|
98
|
+
msg = f"File {path} contains invalid set of quantities"
|
|
99
|
+
raise RuntimeError(msg)
|
|
100
|
+
|
|
101
|
+
md = json.loads(self._h5f.attrs["metadata_json"])
|
|
102
|
+
self._metadata = SimMetaData(**md)
|
|
103
|
+
|
|
104
|
+
self._description = str(self._h5f.attrs.get("description", None))
|
|
105
|
+
|
|
106
|
+
self._t0 = self._metadata.t0
|
|
107
|
+
self._sample_periods = {
|
|
108
|
+
IdxSpace.PHYSICS: self._metadata.physics_dt,
|
|
109
|
+
IdxSpace.PHYSICS_EXT: self._metadata.physics_dt,
|
|
110
|
+
IdxSpace.REGULAR: self._metadata.dt,
|
|
111
|
+
IdxSpace.TELEMETRY: self._metadata.telemetry_dt,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
categories = datasets_metadata_dict()
|
|
115
|
+
|
|
116
|
+
isps: dict[DatasetIdentifier, IdxSpace] = {}
|
|
117
|
+
ranges: dict[IdxSpace, list[tuple[int, int]]] = defaultdict(list)
|
|
118
|
+
for dsid in self.dataset_identifier_set():
|
|
119
|
+
n = dsid[-2]
|
|
120
|
+
cat = categories[n]
|
|
121
|
+
rg = self._read_range(dsid)
|
|
122
|
+
ranges[cat.idxspace].append(rg)
|
|
123
|
+
isps[dsid] = cat.idxspace
|
|
124
|
+
self._isp_by_dsid: Final = isps
|
|
125
|
+
self._range_by_isp: Final = {
|
|
126
|
+
i: _unique_index_range(r) for i, r in ranges.items()
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def _h5f(self) -> h5py.File:
|
|
131
|
+
if self._h5f_raw is None:
|
|
132
|
+
msg = "SimResultFile used after closing it"
|
|
133
|
+
raise RuntimeError(msg)
|
|
134
|
+
return self._h5f_raw
|
|
135
|
+
|
|
136
|
+
def close(self) -> None:
|
|
137
|
+
"""Close file
|
|
138
|
+
|
|
139
|
+
Note the interface provides a context manager, consider using `with`
|
|
140
|
+
mechanism instead
|
|
141
|
+
"""
|
|
142
|
+
if self._h5f_raw is not None:
|
|
143
|
+
self._h5f_raw.close()
|
|
144
|
+
self._h5f_raw = None
|
|
145
|
+
|
|
146
|
+
def __del__(self):
|
|
147
|
+
"""HDF5 file is automatically closed"""
|
|
148
|
+
self.close()
|
|
149
|
+
|
|
150
|
+
def __enter__(self):
|
|
151
|
+
"""Enter context"""
|
|
152
|
+
return self
|
|
153
|
+
|
|
154
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
155
|
+
"""Exit context"""
|
|
156
|
+
self.close()
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def format_version(self) -> Version:
|
|
160
|
+
"""Version number of the file format"""
|
|
161
|
+
return self._version
|
|
162
|
+
|
|
163
|
+
@staticmethod
|
|
164
|
+
def format_specifier() -> SpecifierSet:
|
|
165
|
+
"""Version specifier set compatible with file reader"""
|
|
166
|
+
v = Version(__version__)
|
|
167
|
+
return SpecifierSet(f"=={v}")
|
|
168
|
+
|
|
169
|
+
@classmethod
|
|
170
|
+
def check_file_version(cls, path: str | pathlib.Path) -> tuple[bool, Version]:
|
|
171
|
+
"""Test if file version is compatible with file reader class
|
|
172
|
+
|
|
173
|
+
Arguments:
|
|
174
|
+
path: Path of file to check
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Whether file can be read and the file format version
|
|
178
|
+
"""
|
|
179
|
+
with h5py.File(str(path), "r") as gwf:
|
|
180
|
+
version = Version(gwf.attrs["version_format"])
|
|
181
|
+
return cls.format_specifier().contains(version), version
|
|
182
|
+
|
|
183
|
+
@property
|
|
184
|
+
def is_extended(self) -> bool:
|
|
185
|
+
"""Whether file contains extended set of quantities"""
|
|
186
|
+
return self._extended
|
|
187
|
+
|
|
188
|
+
@property
|
|
189
|
+
def metadata(self) -> SimMetaData:
|
|
190
|
+
"""Simulation metadata"""
|
|
191
|
+
return self._metadata
|
|
192
|
+
|
|
193
|
+
@property
|
|
194
|
+
def description(self) -> str | None:
|
|
195
|
+
"""Description text"""
|
|
196
|
+
return self._description
|
|
197
|
+
|
|
198
|
+
def dataset_identifier_set(self) -> set[DatasetIdentifier]:
|
|
199
|
+
"""Set of all available dataset identifiers"""
|
|
200
|
+
if self.is_extended:
|
|
201
|
+
return SimResultsNumpyFull.dataset_identifier_set()
|
|
202
|
+
return SimResultsNumpyCore.dataset_identifier_set()
|
|
203
|
+
|
|
204
|
+
def idxspace_by_dataset_id(self, dsid: DatasetIdentifier) -> IdxSpace:
|
|
205
|
+
"""Get index space for dataset"""
|
|
206
|
+
return self._isp_by_dsid[dsid]
|
|
207
|
+
|
|
208
|
+
def range_by_idxspace(self, isp: IdxSpace) -> tuple[int, int]:
|
|
209
|
+
"""Get range for given index space"""
|
|
210
|
+
return self._range_by_isp[isp]
|
|
211
|
+
|
|
212
|
+
def range_by_dataset_id(self, dsid: DatasetIdentifier) -> tuple[int, int]:
|
|
213
|
+
"""Get range for given dataset"""
|
|
214
|
+
return self.range_by_idxspace(self.idxspace_by_dataset_id(dsid))
|
|
215
|
+
|
|
216
|
+
def dt_by_idxspace(self, isp: IdxSpace) -> float:
|
|
217
|
+
"""Get sample period for given index space"""
|
|
218
|
+
return self._sample_periods[isp]
|
|
219
|
+
|
|
220
|
+
def dt_by_dataset_id(self, dsid: DatasetIdentifier) -> float:
|
|
221
|
+
"""Get sample period for given dataset"""
|
|
222
|
+
return self.dt_by_idxspace(self.idxspace_by_dataset_id(dsid))
|
|
223
|
+
|
|
224
|
+
def read_by_datset_id(
|
|
225
|
+
self,
|
|
226
|
+
dsid: DatasetIdentifier,
|
|
227
|
+
istart: int | None = None,
|
|
228
|
+
istop: int | None = None,
|
|
229
|
+
) -> np.ndarray:
|
|
230
|
+
"""Read data identified by a `DatasetIdentifier`
|
|
231
|
+
|
|
232
|
+
Optionally, one can restrict the index range. This refers to the logical
|
|
233
|
+
index range given returned `range_by_dataset_id()`, not necessarily starting
|
|
234
|
+
at zero. The returned data will contain indices `istart <= i < istop`
|
|
235
|
+
|
|
236
|
+
Arguments:
|
|
237
|
+
dsid: `DatasetIdentifier` specifying dataset
|
|
238
|
+
istart: Optionally, exclude lower indices
|
|
239
|
+
istop: Optionally, first index to exclude
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
1D numpy array with data
|
|
243
|
+
"""
|
|
244
|
+
dspth = "/".join(dsid)
|
|
245
|
+
ds: h5py.Dataset = self._h5f[dspth]
|
|
246
|
+
aistart, aistop = self.range_by_dataset_id(dsid)
|
|
247
|
+
istart = aistart if istart is None else int(istart)
|
|
248
|
+
istop = aistop if istop is None else int(istop)
|
|
249
|
+
if not aistart <= istart <= istop <= aistop:
|
|
250
|
+
msg = (
|
|
251
|
+
f"SimResultFile: index range {istart}, {istop} not "
|
|
252
|
+
f"available for dataset {dspth}"
|
|
253
|
+
)
|
|
254
|
+
raise RuntimeError(msg)
|
|
255
|
+
if len(ds.shape) == 0: # pylint: disable = no-member
|
|
256
|
+
dat = np.empty(
|
|
257
|
+
istop - istart, dtype=ds.dtype # pylint: disable = no-member
|
|
258
|
+
)
|
|
259
|
+
dat[:] = ds[()]
|
|
260
|
+
return dat
|
|
261
|
+
return ds[istart - aistart : istop - aistart]
|
|
262
|
+
|
|
263
|
+
def read_by_name_and_mosa(
|
|
264
|
+
self,
|
|
265
|
+
name: str,
|
|
266
|
+
mosa: MosaID | str,
|
|
267
|
+
istart: int | None = None,
|
|
268
|
+
istop: int | None = None,
|
|
269
|
+
) -> np.ndarray:
|
|
270
|
+
"""Like `read_by_datset_id` but dataset is specified by name and `MosaID`
|
|
271
|
+
|
|
272
|
+
Arguments:
|
|
273
|
+
name: Dataset name
|
|
274
|
+
mosa: Read dataset for MOSA specified by `MosaID` or MOSA name
|
|
275
|
+
istart: Optionally, exclude lower indices
|
|
276
|
+
istop: Optionally, first index to exclude
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
1D numpy array with data
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
if name not in SimFullDatasetsMOSA.dataset_names():
|
|
283
|
+
msg = f"SimResultFile: invalid per-MOSA dataset {name}"
|
|
284
|
+
raise RuntimeError(msg)
|
|
285
|
+
cat = SimFullDatasetsMOSA.dataset_metadata()[name]
|
|
286
|
+
dsid = make_dataset_id(cat.actual, name, MosaID(mosa).value)
|
|
287
|
+
return self.read_by_datset_id(dsid, istart, istop)
|
|
288
|
+
|
|
289
|
+
def read_by_name_and_sat(
|
|
290
|
+
self,
|
|
291
|
+
name: str,
|
|
292
|
+
sc: SatID | str,
|
|
293
|
+
istart: int | None = None,
|
|
294
|
+
istop: int | None = None,
|
|
295
|
+
) -> np.ndarray:
|
|
296
|
+
"""Like `read_by_datset_id` but dataset is specified by name and `SatID`
|
|
297
|
+
|
|
298
|
+
Arguments:
|
|
299
|
+
name: Dataset name
|
|
300
|
+
sc: Read dataset for spacecraft specified by `SatID` or spacecraft name
|
|
301
|
+
istart: Optionally, exclude lower indices
|
|
302
|
+
istop: Optionally, first index to exclude
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
1D numpy array with data
|
|
306
|
+
"""
|
|
307
|
+
if name not in SimFullDatasetsSat.dataset_names():
|
|
308
|
+
msg = f"SimResultFile: invalid per-spacecraft dataset {name}"
|
|
309
|
+
raise RuntimeError(msg)
|
|
310
|
+
cat = SimFullDatasetsSat.dataset_metadata()[name]
|
|
311
|
+
dsid = make_dataset_id(cat.actual, name, SatID(sc).value)
|
|
312
|
+
return self.read_by_datset_id(dsid, istart, istop)
|
|
313
|
+
|
|
314
|
+
def _read_range(self, dsid: DatasetIdentifier) -> tuple[int, int]:
|
|
315
|
+
"""Get the index range available for a given dataset
|
|
316
|
+
|
|
317
|
+
The available indices `i` are in the range `istart <= i < istop`.
|
|
318
|
+
|
|
319
|
+
Arguments:
|
|
320
|
+
dsid: `DatasetIdentifier` specifying the dataset
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
Tuple `(istart, istop)`
|
|
324
|
+
"""
|
|
325
|
+
dspth = "/".join(dsid)
|
|
326
|
+
ds: h5py.Dataset = self._h5f[dspth]
|
|
327
|
+
istart = int(ds.attrs[DataStorageHDF5.attr_name_index_start])
|
|
328
|
+
istop = int(ds.attrs[DataStorageHDF5.attr_name_index_stop])
|
|
329
|
+
return (istart, istop)
|
|
330
|
+
|
|
331
|
+
def _restrict_range_isp(
|
|
332
|
+
self,
|
|
333
|
+
isp: IdxSpace,
|
|
334
|
+
t_min: float | None = None,
|
|
335
|
+
t_max: float | None = None,
|
|
336
|
+
) -> tuple[int, int]:
|
|
337
|
+
"""Compute index range within given time interval for a given dataset"""
|
|
338
|
+
dt = self.dt_by_idxspace(isp)
|
|
339
|
+
istart, istop = self.range_by_idxspace(isp)
|
|
340
|
+
if t_min is None:
|
|
341
|
+
i0 = istart
|
|
342
|
+
else:
|
|
343
|
+
i0 = int(np.ceil((t_min - self._t0) / dt))
|
|
344
|
+
|
|
345
|
+
if t_max is None:
|
|
346
|
+
i1 = istop
|
|
347
|
+
else:
|
|
348
|
+
i1 = int(np.ceil((t_max - self._t0) / dt))
|
|
349
|
+
|
|
350
|
+
return i0, i1
|
|
351
|
+
|
|
352
|
+
def _restrict_ranges(
|
|
353
|
+
self,
|
|
354
|
+
t_min: float | None = None,
|
|
355
|
+
t_max: float | None = None,
|
|
356
|
+
) -> dict[IdxSpace, tuple[int, int]]:
|
|
357
|
+
"""Compute index ranges within given time interval for datasets"""
|
|
358
|
+
return {
|
|
359
|
+
isp: self._restrict_range_isp(isp, t_min, t_max)
|
|
360
|
+
for isp in self._range_by_isp
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
def _read_datasets(
|
|
364
|
+
self,
|
|
365
|
+
cls: type[_T],
|
|
366
|
+
t_min: float | None = None,
|
|
367
|
+
t_max: float | None = None,
|
|
368
|
+
) -> _T:
|
|
369
|
+
"""Read datasets into a `DataStorageNumpy` instance"""
|
|
370
|
+
datasets = cls.dataset_identifier_set()
|
|
371
|
+
ranges_isp = self._restrict_ranges(t_min, t_max)
|
|
372
|
+
ranges_dsid = {
|
|
373
|
+
dsid: ranges_isp[self.idxspace_by_dataset_id(dsid)] for dsid in datasets
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
stb = self.as_stream_bundle(datasets, ranges_dsid)
|
|
377
|
+
store = store_bundle_numpy(stb)
|
|
378
|
+
return cls(store.as_dict(), ranges_isp, self.metadata.asdict())
|
|
379
|
+
|
|
380
|
+
def read_full(
|
|
381
|
+
self, t_min: float | None = None, t_max: float | None = None
|
|
382
|
+
) -> SimResultsNumpyFull:
|
|
383
|
+
"""Read extended set of quantities into memory as `SimResultsNumpyFull` instance
|
|
384
|
+
|
|
385
|
+
If the file does not contain the extended set, an RuntimeError is raised.
|
|
386
|
+
|
|
387
|
+
Optionally, on can restrict the time range for which the data samples are
|
|
388
|
+
read. This does not change the index space, i.e. which indices refer to which
|
|
389
|
+
times. It only changes the index range of the datasets, available through
|
|
390
|
+
the `sat_ranges` and `mosa_ranges` attributes of `SimResultsNumpyFull`.
|
|
391
|
+
|
|
392
|
+
Arguments:
|
|
393
|
+
t_min: Optionally, only read samples at later times
|
|
394
|
+
t_max: Optionally, only read samples at earlier times
|
|
395
|
+
|
|
396
|
+
Returns:
|
|
397
|
+
`SimResultsNumpyFull` instance with data.
|
|
398
|
+
"""
|
|
399
|
+
|
|
400
|
+
if not self.is_extended:
|
|
401
|
+
msg = "SimResultFile: cannot read extended results from basic result file"
|
|
402
|
+
raise RuntimeError(msg)
|
|
403
|
+
return self._read_datasets(SimResultsNumpyFull, t_min, t_max)
|
|
404
|
+
|
|
405
|
+
def read_core(
|
|
406
|
+
self, t_min: float | None = None, t_max: float | None = None
|
|
407
|
+
) -> SimResultsNumpyCore:
|
|
408
|
+
"""Same as `read_full` but restricted to basic set of quantities
|
|
409
|
+
|
|
410
|
+
Arguments:
|
|
411
|
+
t_min: Optionally, only read samples at later times
|
|
412
|
+
t_max: Optionally, only read samples at earlier times
|
|
413
|
+
|
|
414
|
+
Returns:
|
|
415
|
+
`SimResultsNumpyCore` instance with data.
|
|
416
|
+
"""
|
|
417
|
+
return self._read_datasets(SimResultsNumpyCore, t_min, t_max)
|
|
418
|
+
|
|
419
|
+
def as_stream_bundle(
|
|
420
|
+
self,
|
|
421
|
+
datasets: set[DatasetIdentifier] | None = None,
|
|
422
|
+
ranges: dict[DatasetIdentifier, tuple[int, int]] | None = None,
|
|
423
|
+
) -> StreamBundle:
|
|
424
|
+
"""Represent datasets in the file as `StreamBundle`
|
|
425
|
+
|
|
426
|
+
Arguments:
|
|
427
|
+
datasets: Set of quantities to include
|
|
428
|
+
ranges: Dictionary with optional entris restricting dataset index range
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
StreamBundle with specified datasets as outputs.
|
|
432
|
+
"""
|
|
433
|
+
if datasets is None:
|
|
434
|
+
datasets = self.dataset_identifier_set()
|
|
435
|
+
return instru_hdf5_file_as_stream_bundle(self._h5f, datasets, ranges=ranges)
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def sim_result_file(
|
|
439
|
+
path: pathlib.Path | str, only_compatible: bool = False
|
|
440
|
+
) -> SimResultFile | SimResultFile_V2_0_0:
|
|
441
|
+
"""Open simulation result file
|
|
442
|
+
|
|
443
|
+
This provides an interface with methods for reading the file.
|
|
444
|
+
The returned interface depends on the file format version. To require
|
|
445
|
+
the interface for the current version, use the option `only_compatible=True`.
|
|
446
|
+
In this case, trying to read a file that cannot be represented through
|
|
447
|
+
the current interface raises an exception.
|
|
448
|
+
|
|
449
|
+
Arguments:
|
|
450
|
+
path: Path of simulation result file
|
|
451
|
+
only_compatible: If False (default) allow reading old formats
|
|
452
|
+
|
|
453
|
+
Returns:
|
|
454
|
+
SimResultFile instance for reading file data
|
|
455
|
+
"""
|
|
456
|
+
|
|
457
|
+
readers: list[type[SimResultFile] | type[SimResultFile_V2_0_0]] = [SimResultFile]
|
|
458
|
+
if not only_compatible:
|
|
459
|
+
readers.append(SimResultFile_V2_0_0)
|
|
460
|
+
|
|
461
|
+
version: Version
|
|
462
|
+
for reader in readers:
|
|
463
|
+
compatible, version = reader.check_file_version(path)
|
|
464
|
+
if compatible:
|
|
465
|
+
return reader(path)
|
|
466
|
+
|
|
467
|
+
msg = f"Unsupported simulation result file version '{version}'"
|
|
468
|
+
raise RuntimeError(msg)
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Besides chunked processing, it also allows reading all data into memory at once,
|
|
11
|
-
collected in a SimResultsNumpyCore or SimResultsNumpyFull instance.
|
|
1
|
+
# pylint: disable = duplicate-code
|
|
2
|
+
# The duplication is on purpose, we do not want to entangle readers for
|
|
3
|
+
# different formats, even though they are very similar.
|
|
4
|
+
"""File reader for old 2.0.0 instrument file format
|
|
5
|
+
|
|
6
|
+
Files created by version 2.0.0 cannot be represented by the current interface
|
|
7
|
+
and data structures because they are missing two metadata items. To support
|
|
8
|
+
reading them, we keep the old interface here, which can be used by
|
|
9
|
+
`instru_file_reader.sim_results_file` to read the old format.
|
|
12
10
|
"""
|
|
13
11
|
|
|
14
12
|
import json
|
|
@@ -18,8 +16,10 @@ from typing import Final, TypeVar
|
|
|
18
16
|
|
|
19
17
|
import h5py
|
|
20
18
|
import numpy as np
|
|
19
|
+
from packaging.specifiers import SpecifierSet
|
|
20
|
+
from packaging.version import Version
|
|
21
21
|
|
|
22
|
-
from lisainstrument.instru.
|
|
22
|
+
from lisainstrument.instru.instru_store_v2_0_0 import (
|
|
23
23
|
IdxSpace,
|
|
24
24
|
SimFullDatasetsMOSA,
|
|
25
25
|
SimFullDatasetsSat,
|
|
@@ -33,7 +33,7 @@ from lisainstrument.orbiting.constellation_enums import MosaID, SatID
|
|
|
33
33
|
from lisainstrument.streams import DatasetIdentifier, StreamBundle
|
|
34
34
|
from lisainstrument.streams.hdf5_store import (
|
|
35
35
|
DataStorageHDF5,
|
|
36
|
-
|
|
36
|
+
instru_hdf5_file_as_stream_bundle,
|
|
37
37
|
)
|
|
38
38
|
from lisainstrument.streams.numpy_store import store_bundle_numpy
|
|
39
39
|
|
|
@@ -70,7 +70,12 @@ class SimResultFile:
|
|
|
70
70
|
Arguments:
|
|
71
71
|
path: Path of the a HDF5 file created by store_instru_hdf5
|
|
72
72
|
"""
|
|
73
|
-
self.
|
|
73
|
+
self._h5f_raw = h5py.File(str(path), "r")
|
|
74
|
+
self._version: Final = Version(self._h5f.attrs["version_format"])
|
|
75
|
+
|
|
76
|
+
if not SimResultFile.format_specifier().contains(self._version):
|
|
77
|
+
msg = f"File {path} version {self._version} not compatible with file reader"
|
|
78
|
+
raise RuntimeError(msg)
|
|
74
79
|
|
|
75
80
|
ds_actual = set(self._h5f.keys()) - {"debug"}
|
|
76
81
|
ds_debug = set(self._h5f["debug"].keys())
|
|
@@ -112,9 +117,59 @@ class SimResultFile:
|
|
|
112
117
|
i: _unique_index_range(r) for i, r in ranges.items()
|
|
113
118
|
}
|
|
114
119
|
|
|
120
|
+
@property
|
|
121
|
+
def _h5f(self) -> h5py.File:
|
|
122
|
+
if self._h5f_raw is None:
|
|
123
|
+
msg = "SimResultFile used after closing it"
|
|
124
|
+
raise RuntimeError(msg)
|
|
125
|
+
return self._h5f_raw
|
|
126
|
+
|
|
127
|
+
def close(self) -> None:
|
|
128
|
+
"""Close file
|
|
129
|
+
|
|
130
|
+
Note the interface provides a context manager, consider using `with`
|
|
131
|
+
mechanism instead
|
|
132
|
+
"""
|
|
133
|
+
if self._h5f_raw is not None:
|
|
134
|
+
self._h5f_raw.close()
|
|
135
|
+
self._h5f_raw = None
|
|
136
|
+
|
|
115
137
|
def __del__(self):
|
|
116
|
-
"""
|
|
117
|
-
self.
|
|
138
|
+
"""HDF5 file is automatically closed"""
|
|
139
|
+
self.close()
|
|
140
|
+
|
|
141
|
+
def __enter__(self):
|
|
142
|
+
"""Enter context"""
|
|
143
|
+
return self
|
|
144
|
+
|
|
145
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
146
|
+
"""Exit context"""
|
|
147
|
+
self.close()
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def format_version(self) -> Version:
|
|
151
|
+
"""Version number of the file format"""
|
|
152
|
+
return self._version
|
|
153
|
+
|
|
154
|
+
@staticmethod
|
|
155
|
+
def format_specifier() -> SpecifierSet:
|
|
156
|
+
"""Version specifier set compatible with file reader"""
|
|
157
|
+
v = Version("2.0.0")
|
|
158
|
+
return SpecifierSet(f"=={v}")
|
|
159
|
+
|
|
160
|
+
@classmethod
|
|
161
|
+
def check_file_version(cls, path: str | pathlib.Path) -> tuple[bool, Version]:
|
|
162
|
+
"""Test if file version is compatible with file reader class
|
|
163
|
+
|
|
164
|
+
Arguments:
|
|
165
|
+
path: Path of file to check
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Whether file can be read and the file format version
|
|
169
|
+
"""
|
|
170
|
+
with h5py.File(str(path), "r") as gwf:
|
|
171
|
+
version = Version(gwf.attrs["version_format"])
|
|
172
|
+
return cls.format_specifier().contains(version), version
|
|
118
173
|
|
|
119
174
|
@property
|
|
120
175
|
def is_extended(self) -> bool:
|
|
@@ -146,15 +201,15 @@ class SimResultFile:
|
|
|
146
201
|
return self._range_by_isp[isp]
|
|
147
202
|
|
|
148
203
|
def range_by_dataset_id(self, dsid: DatasetIdentifier) -> tuple[int, int]:
|
|
149
|
-
"""Get range for given
|
|
204
|
+
"""Get range for given dataset"""
|
|
150
205
|
return self.range_by_idxspace(self.idxspace_by_dataset_id(dsid))
|
|
151
206
|
|
|
152
207
|
def dt_by_idxspace(self, isp: IdxSpace) -> float:
|
|
153
|
-
"""Get
|
|
208
|
+
"""Get sample period for given index space"""
|
|
154
209
|
return self._sample_periods[isp]
|
|
155
210
|
|
|
156
211
|
def dt_by_dataset_id(self, dsid: DatasetIdentifier) -> float:
|
|
157
|
-
"""Get
|
|
212
|
+
"""Get sample period for given dataset"""
|
|
158
213
|
return self.dt_by_idxspace(self.idxspace_by_dataset_id(dsid))
|
|
159
214
|
|
|
160
215
|
def read_by_datset_id(
|
|
@@ -368,4 +423,4 @@ class SimResultFile:
|
|
|
368
423
|
"""
|
|
369
424
|
if datasets is None:
|
|
370
425
|
datasets = self.dataset_identifier_set()
|
|
371
|
-
return
|
|
426
|
+
return instru_hdf5_file_as_stream_bundle(self._h5f, datasets, ranges=ranges)
|