dag-modelling 0.12__py3-none-any.whl
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.
- dag_modelling/__init__.py +0 -0
- dag_modelling/bundles/__init__.py +0 -0
- dag_modelling/bundles/file_reader.py +592 -0
- dag_modelling/bundles/load_array.py +100 -0
- dag_modelling/bundles/load_graph.py +163 -0
- dag_modelling/bundles/load_hist.py +169 -0
- dag_modelling/bundles/load_parameters.py +489 -0
- dag_modelling/bundles/load_record.py +135 -0
- dag_modelling/bundles/make_y_parameters_for_x.py +72 -0
- dag_modelling/core/__init__.py +2 -0
- dag_modelling/core/data_descriptor.py +125 -0
- dag_modelling/core/edges.py +278 -0
- dag_modelling/core/exception.py +115 -0
- dag_modelling/core/flags_descriptor.py +123 -0
- dag_modelling/core/graph.py +197 -0
- dag_modelling/core/graph_base.py +45 -0
- dag_modelling/core/input.py +285 -0
- dag_modelling/core/input_strategy.py +292 -0
- dag_modelling/core/iter.py +8 -0
- dag_modelling/core/iterators.py +44 -0
- dag_modelling/core/labels.py +693 -0
- dag_modelling/core/make_fcn.py +117 -0
- dag_modelling/core/meta_node.py +307 -0
- dag_modelling/core/node.py +712 -0
- dag_modelling/core/node_base.py +187 -0
- dag_modelling/core/output.py +533 -0
- dag_modelling/core/storage.py +903 -0
- dag_modelling/core/type_functions/__init__.py +41 -0
- dag_modelling/core/type_functions/axes_type_functions.py +289 -0
- dag_modelling/core/type_functions/copy_type_functions.py +101 -0
- dag_modelling/core/type_functions/input_type_functions.py +379 -0
- dag_modelling/core/type_functions/output_type_functions.py +46 -0
- dag_modelling/core/type_functions/tools_for_type_functions.py +62 -0
- dag_modelling/core/types.py +8 -0
- dag_modelling/export/__init__.py +0 -0
- dag_modelling/export/to_root.py +262 -0
- dag_modelling/lib/__init__.py +0 -0
- dag_modelling/lib/abstract/__init__.py +7 -0
- dag_modelling/lib/abstract/block_to_one_node.py +255 -0
- dag_modelling/lib/abstract/many_to_one_node.py +243 -0
- dag_modelling/lib/abstract/one_to_one_node.py +174 -0
- dag_modelling/lib/arithmetic.py +195 -0
- dag_modelling/lib/axis/__init__.py +5 -0
- dag_modelling/lib/axis/bin_center.py +47 -0
- dag_modelling/lib/axis/bin_width.py +48 -0
- dag_modelling/lib/axis/mesh_to_edges.py +48 -0
- dag_modelling/lib/calculus/__init__.py +3 -0
- dag_modelling/lib/calculus/jacobian.py +161 -0
- dag_modelling/lib/common/__init__.py +17 -0
- dag_modelling/lib/common/array.py +230 -0
- dag_modelling/lib/common/cache.py +20 -0
- dag_modelling/lib/common/concatenation.py +57 -0
- dag_modelling/lib/common/copy.py +14 -0
- dag_modelling/lib/common/dummy.py +13 -0
- dag_modelling/lib/common/proxy.py +26 -0
- dag_modelling/lib/common/view.py +77 -0
- dag_modelling/lib/common/view_concat.py +51 -0
- dag_modelling/lib/exponential.py +73 -0
- dag_modelling/lib/hist/__init__.py +15 -0
- dag_modelling/lib/hist/axis_distortion_matrix.py +196 -0
- dag_modelling/lib/hist/axis_distortion_matrix_linear.py +181 -0
- dag_modelling/lib/hist/axis_distortion_matrix_pointwise.py +373 -0
- dag_modelling/lib/hist/hist_smear_normal_matrix_b_c.py +125 -0
- dag_modelling/lib/hist/rebin.py +140 -0
- dag_modelling/lib/hist/rebin_matrix.py +211 -0
- dag_modelling/lib/integration/__init__.py +7 -0
- dag_modelling/lib/integration/integrator.py +149 -0
- dag_modelling/lib/integration/integrator_core.py +287 -0
- dag_modelling/lib/integration/integrator_sampler.py +296 -0
- dag_modelling/lib/interpolation/__init__.py +7 -0
- dag_modelling/lib/interpolation/interpolator.py +144 -0
- dag_modelling/lib/interpolation/interpolator_core.py +399 -0
- dag_modelling/lib/interpolation/segment_index.py +143 -0
- dag_modelling/lib/linalg/__init__.py +13 -0
- dag_modelling/lib/linalg/cholesky.py +57 -0
- dag_modelling/lib/linalg/linear_function.py +43 -0
- dag_modelling/lib/linalg/matrix_product_AB.py +82 -0
- dag_modelling/lib/linalg/matrix_product_DDt.py +38 -0
- dag_modelling/lib/linalg/matrix_product_DVDt.py +66 -0
- dag_modelling/lib/linalg/vector_matrix_product.py +104 -0
- dag_modelling/lib/normalization/__init__.py +5 -0
- dag_modelling/lib/normalization/normalize_matrix.py +85 -0
- dag_modelling/lib/normalization/renormalize_diag.py +121 -0
- dag_modelling/lib/parameters/__init__.py +3 -0
- dag_modelling/lib/parameters/par_array_input.py +64 -0
- dag_modelling/lib/physics/__init__.py +4 -0
- dag_modelling/lib/physics/energy_resolution.py +207 -0
- dag_modelling/lib/physics/energy_resolution_sigma_rel_a_b_c.py +95 -0
- dag_modelling/lib/statistics/__init__.py +21 -0
- dag_modelling/lib/statistics/chi2.py +170 -0
- dag_modelling/lib/statistics/cnp_stat.py +117 -0
- dag_modelling/lib/statistics/covariance_matrix_group.py +271 -0
- dag_modelling/lib/statistics/covmatrix_from_cormatrix.py +54 -0
- dag_modelling/lib/statistics/log_poisson_ratio.py +97 -0
- dag_modelling/lib/statistics/log_prod_diag.py +77 -0
- dag_modelling/lib/statistics/monte_carlo.py +471 -0
- dag_modelling/lib/statistics/normalize_correlated_vars.py +117 -0
- dag_modelling/lib/statistics/normalize_correlated_vars_two_ways.py +190 -0
- dag_modelling/lib/summation/__init__.py +15 -0
- dag_modelling/lib/summation/array_sum.py +32 -0
- dag_modelling/lib/summation/el_sum_sq.py +39 -0
- dag_modelling/lib/summation/partial_sums.py +74 -0
- dag_modelling/lib/summation/sum_mat_or_diag.py +88 -0
- dag_modelling/lib/summation/sum_sq.py +41 -0
- dag_modelling/lib/summation/weighted_sum.py +75 -0
- dag_modelling/lib/summation/weighted_sum_args.py +77 -0
- dag_modelling/lib/trigonometry.py +105 -0
- dag_modelling/parameters/__init__.py +9 -0
- dag_modelling/parameters/gaussian_parameter.py +140 -0
- dag_modelling/parameters/gaussian_parameters.py +296 -0
- dag_modelling/parameters/parameter.py +170 -0
- dag_modelling/parameters/parameters.py +219 -0
- dag_modelling/plot/__init__.py +0 -0
- dag_modelling/plot/graphviz.py +871 -0
- dag_modelling/plot/plot.py +763 -0
- dag_modelling/tools/__init__.py +0 -0
- dag_modelling/tools/formatter.py +74 -0
- dag_modelling/tools/iter.py +16 -0
- dag_modelling/tools/logger.py +62 -0
- dag_modelling/tools/profiling/__init__.py +18 -0
- dag_modelling/tools/profiling/count_calls_profiler.py +100 -0
- dag_modelling/tools/profiling/delay_node.py +41 -0
- dag_modelling/tools/profiling/fit_simulation_profiling.py +203 -0
- dag_modelling/tools/profiling/framework_profiler.py +142 -0
- dag_modelling/tools/profiling/memory_profiler.py +176 -0
- dag_modelling/tools/profiling/node_profiler.py +131 -0
- dag_modelling/tools/profiling/profiler.py +222 -0
- dag_modelling/tools/profiling/timer_profiler.py +198 -0
- dag_modelling/tools/profiling/utils.py +85 -0
- dag_modelling/tools/save_records.py +123 -0
- dag_modelling/tools/schema.py +180 -0
- dag_modelling-0.12.dist-info/METADATA +126 -0
- dag_modelling-0.12.dist-info/RECORD +136 -0
- dag_modelling-0.12.dist-info/WHEEL +5 -0
- dag_modelling-0.12.dist-info/licenses/LICENSE +21 -0
- dag_modelling-0.12.dist-info/top_level.txt +1 -0
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from contextlib import suppress
|
|
4
|
+
from os import listdir
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from numpy import concatenate, double, dtype, frombuffer, linspace, ndarray
|
|
9
|
+
|
|
10
|
+
from nested_mapping.tools.map import make_reorder_function
|
|
11
|
+
from nested_mapping.typing import properkey
|
|
12
|
+
|
|
13
|
+
from ..tools.logger import INFO1, INFO2, INFO3, logger
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from collections.abc import Generator, Sequence
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
import ROOT
|
|
20
|
+
from numpy.typing import NDArray
|
|
21
|
+
|
|
22
|
+
from nested_mapping.typing import KeyLike, TupleKey
|
|
23
|
+
|
|
24
|
+
file_readers = {}
|
|
25
|
+
|
|
26
|
+
_log_float_format = ".3g"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class HistGetter:
|
|
30
|
+
__slots__ = ()
|
|
31
|
+
|
|
32
|
+
def __getitem__(self, names: tuple[str | Path, str]) -> tuple[NDArray, NDArray]:
|
|
33
|
+
file_name, object_name = names
|
|
34
|
+
fr = FileReader[file_name]
|
|
35
|
+
return fr.get_hist(object_name)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
_HistGetter = HistGetter()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class GraphGetter:
|
|
42
|
+
__slots__ = ()
|
|
43
|
+
|
|
44
|
+
def __getitem__(self, names: tuple[str | Path, str]) -> tuple[NDArray, NDArray]:
|
|
45
|
+
file_name, object_name = names
|
|
46
|
+
fr = FileReader[file_name]
|
|
47
|
+
return fr.get_graph(object_name)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
_GraphGetter = GraphGetter()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ArrayGetter:
|
|
54
|
+
__slots__ = ()
|
|
55
|
+
|
|
56
|
+
def __getitem__(self, names: tuple[str | Path, str]) -> NDArray:
|
|
57
|
+
file_name, object_name = names
|
|
58
|
+
fr = FileReader[file_name]
|
|
59
|
+
return fr.get_array(object_name)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
_ArrayGetter = ArrayGetter()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class RecordGetter:
|
|
66
|
+
__slots__ = ()
|
|
67
|
+
|
|
68
|
+
def __getitem__(self, names: tuple[str | Path, str]) -> NDArray | dict[str, NDArray]:
|
|
69
|
+
file_name, object_name = names
|
|
70
|
+
fr = FileReader[file_name]
|
|
71
|
+
return fr.get_record(object_name)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
_RecordGetter = RecordGetter()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class FileReaderMeta(type):
|
|
78
|
+
"""Metaclass for `FileReader` class, implementing `FileReader[file_name]`
|
|
79
|
+
method."""
|
|
80
|
+
|
|
81
|
+
_opened_files: dict[str, FileReader] = {}
|
|
82
|
+
_last_used_file: str = ""
|
|
83
|
+
|
|
84
|
+
def __init__(self, name: str, parents: tuple, args: dict) -> None:
|
|
85
|
+
"""Register the file reader based on the `_extension`"""
|
|
86
|
+
super().__init__(name, parents, args)
|
|
87
|
+
try:
|
|
88
|
+
ext = args["_extension"]
|
|
89
|
+
except KeyError as e:
|
|
90
|
+
raise e
|
|
91
|
+
else:
|
|
92
|
+
file_readers[ext] = self
|
|
93
|
+
|
|
94
|
+
def __getitem__(self, file_name: str | Path) -> FileReader:
|
|
95
|
+
file_name_str = file_name if isinstance(file_name, str) else str(file_name)
|
|
96
|
+
try:
|
|
97
|
+
ret = self._opened_files[file_name_str]
|
|
98
|
+
action = "Use" if file_name_str != self._last_used_file else None
|
|
99
|
+
except KeyError:
|
|
100
|
+
ret = FileReader.open(file_name)
|
|
101
|
+
action = "Read"
|
|
102
|
+
|
|
103
|
+
if action:
|
|
104
|
+
logger.log(INFO1, f"{action}: {file_name_str}")
|
|
105
|
+
|
|
106
|
+
self._opened_files[file_name_str] = ret
|
|
107
|
+
self._last_used_file = file_name_str
|
|
108
|
+
|
|
109
|
+
return ret
|
|
110
|
+
|
|
111
|
+
def __enter__(self) -> None:
|
|
112
|
+
pass
|
|
113
|
+
|
|
114
|
+
def __exit__(self, *args, **kwargs) -> None:
|
|
115
|
+
self.release_files()
|
|
116
|
+
|
|
117
|
+
def release_files(self) -> None:
|
|
118
|
+
for k, v in list(self._opened_files.items()):
|
|
119
|
+
v._close()
|
|
120
|
+
del self._opened_files[k]
|
|
121
|
+
|
|
122
|
+
logger.log(INFO3, f"Close: {v._file_name!s}")
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def array(self) -> ArrayGetter:
|
|
126
|
+
return _ArrayGetter
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def graph(self) -> GraphGetter:
|
|
130
|
+
return _GraphGetter
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def hist(self) -> HistGetter:
|
|
134
|
+
return _HistGetter
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def record(self) -> RecordGetter:
|
|
138
|
+
return _RecordGetter
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class FileReader(metaclass=FileReaderMeta):
|
|
142
|
+
_extension: str = ""
|
|
143
|
+
_file: Any = None
|
|
144
|
+
_file_name: Path = Path("")
|
|
145
|
+
_opened_files: dict[str, FileReader] = FileReaderMeta._opened_files
|
|
146
|
+
_read_objects: dict[str, Any]
|
|
147
|
+
|
|
148
|
+
def __init__(self, file_name: str | Path):
|
|
149
|
+
self._file_name = Path(file_name)
|
|
150
|
+
self._read_objects = {}
|
|
151
|
+
|
|
152
|
+
@classmethod
|
|
153
|
+
def open(cls, file_name: str | Path) -> FileReader:
|
|
154
|
+
file_path = file_name if isinstance(file_name, Path) else Path(file_name)
|
|
155
|
+
ext = file_path.suffix
|
|
156
|
+
|
|
157
|
+
try:
|
|
158
|
+
cls = file_readers[ext]
|
|
159
|
+
except KeyError as e:
|
|
160
|
+
raise ValueError(
|
|
161
|
+
f"Do not know how to load ext {ext}. Available file_readers:"
|
|
162
|
+
f" {', '.join(file_readers)}"
|
|
163
|
+
) from e
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
return cls(file_name)
|
|
167
|
+
except FileNotFoundError as e:
|
|
168
|
+
raise FileNotFoundError(f"Can not open file {file_name!s} (loader {ext})") from e
|
|
169
|
+
|
|
170
|
+
def _close(self) -> None:
|
|
171
|
+
self._read_objects = {}
|
|
172
|
+
|
|
173
|
+
def keys(self) -> tuple[str, ...]:
|
|
174
|
+
raise RuntimeError("not implemented method")
|
|
175
|
+
|
|
176
|
+
def _get_object_impl(self, object_name: str, **kwargs) -> Any:
|
|
177
|
+
raise RuntimeError("not implemented method")
|
|
178
|
+
|
|
179
|
+
def _get_object(self, object_name: str, **kwargs) -> Any:
|
|
180
|
+
object_name = object_name.replace(".", "_")
|
|
181
|
+
with suppress(KeyError):
|
|
182
|
+
return self._read_objects[object_name]
|
|
183
|
+
|
|
184
|
+
try:
|
|
185
|
+
self._read_objects[object_name] = (
|
|
186
|
+
object := self._get_object_impl(object_name, **kwargs)
|
|
187
|
+
)
|
|
188
|
+
return object
|
|
189
|
+
except KeyError as e:
|
|
190
|
+
raise KeyError(f"Can not read {object_name} from {self._file_name!s}") from e
|
|
191
|
+
|
|
192
|
+
def _get_graph(self, object_name: str) -> tuple[NDArray, NDArray]:
|
|
193
|
+
raise RuntimeError("not implemented method")
|
|
194
|
+
|
|
195
|
+
def get_graph(self, object_name: str) -> tuple[NDArray, NDArray]:
|
|
196
|
+
x, y = self._get_graph(object_name)
|
|
197
|
+
logger.log(
|
|
198
|
+
INFO2,
|
|
199
|
+
f"graph {object_name} ({len(y)}): x"
|
|
200
|
+
f" {x[0]:{_log_float_format}}→{x[-1]:{_log_float_format}},"
|
|
201
|
+
f" ymin={y.min():{_log_float_format}}, ymax={y.max():{_log_float_format}}",
|
|
202
|
+
)
|
|
203
|
+
return x, y
|
|
204
|
+
|
|
205
|
+
def _get_hist(self, object_name: str) -> tuple[NDArray, NDArray]:
|
|
206
|
+
raise RuntimeError("not implemented method")
|
|
207
|
+
|
|
208
|
+
def get_hist(self, object_name: str) -> tuple[NDArray, NDArray]:
|
|
209
|
+
x, y = self._get_hist(object_name)
|
|
210
|
+
logger.log(
|
|
211
|
+
INFO2,
|
|
212
|
+
f"hist {object_name} ({len(y)}): x"
|
|
213
|
+
f" {x[0]:{_log_float_format}}→{x[-1]:{_log_float_format}},"
|
|
214
|
+
f" min={y.min():{_log_float_format}}, max={y.max():{_log_float_format}},"
|
|
215
|
+
f" Σh={y.sum():{_log_float_format}}",
|
|
216
|
+
)
|
|
217
|
+
return x, y
|
|
218
|
+
|
|
219
|
+
def _get_array(self, object_name: str) -> NDArray:
|
|
220
|
+
raise RuntimeError("not implemented method")
|
|
221
|
+
|
|
222
|
+
def get_array(self, object_name: str) -> NDArray:
|
|
223
|
+
a = self._get_array(object_name)
|
|
224
|
+
logger.log(
|
|
225
|
+
INFO2,
|
|
226
|
+
f"array {object_name} {'x'.join(map(str,a.shape))}: min={a.min():{_log_float_format}},"
|
|
227
|
+
f" max={a.max():{_log_float_format}}, Σ={a.sum():{_log_float_format}}",
|
|
228
|
+
)
|
|
229
|
+
return a
|
|
230
|
+
|
|
231
|
+
def _get_record(self, object_name: str) -> NDArray | dict[str, NDArray]:
|
|
232
|
+
raise RuntimeError("not implemented method")
|
|
233
|
+
|
|
234
|
+
def get_record(self, object_name: str) -> NDArray | dict[str, NDArray]:
|
|
235
|
+
rec = self._get_record(object_name)
|
|
236
|
+
|
|
237
|
+
match rec:
|
|
238
|
+
case ndarray():
|
|
239
|
+
nrows = rec.shape[0]
|
|
240
|
+
columns = ", ".join(rec.dtype.names) if rec.dtype.names else "???"
|
|
241
|
+
case dict():
|
|
242
|
+
nrows = next(iter(rec.values())).shape[0]
|
|
243
|
+
columns = ", ".join(rec.keys())
|
|
244
|
+
case _:
|
|
245
|
+
nrows = -1
|
|
246
|
+
columns = "???"
|
|
247
|
+
|
|
248
|
+
logger.log(
|
|
249
|
+
INFO2,
|
|
250
|
+
f"record {object_name} ({nrows}):" f" {columns}",
|
|
251
|
+
)
|
|
252
|
+
return rec
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class FileReaderArray(FileReader):
|
|
256
|
+
_extension: str = ""
|
|
257
|
+
|
|
258
|
+
def _get_graph(self, object_name: str) -> tuple[NDArray, NDArray]:
|
|
259
|
+
return self._get_xy(object_name)
|
|
260
|
+
|
|
261
|
+
def _get_hist(self, object_name: str) -> tuple[NDArray, NDArray]:
|
|
262
|
+
emin, emax, h = self._get_emin_emax_h(object_name)
|
|
263
|
+
if not (emin[1:] == emax[:-1]).all():
|
|
264
|
+
raise ValueError("Inconsistent histogram edges")
|
|
265
|
+
edges = concatenate((emin, emax[-1:]))
|
|
266
|
+
return edges, h
|
|
267
|
+
|
|
268
|
+
def _get_array(self, object_name: str) -> NDArray:
|
|
269
|
+
return self._get_object(object_name)
|
|
270
|
+
|
|
271
|
+
def _get_record(self, object_name: str) -> NDArray:
|
|
272
|
+
return self._get_object(object_name)
|
|
273
|
+
|
|
274
|
+
def _get_xy(self, object_name: str) -> tuple[NDArray, NDArray]:
|
|
275
|
+
data = self._get_object(object_name)
|
|
276
|
+
cols = data.dtype.names
|
|
277
|
+
return data[cols[0]], data[cols[1]]
|
|
278
|
+
|
|
279
|
+
def _get_emin_emax_h(self, object_name: str) -> tuple[NDArray, NDArray, NDArray]:
|
|
280
|
+
data = self._get_object(object_name)
|
|
281
|
+
cols = data.dtype.names
|
|
282
|
+
return data[cols[0]], data[cols[1]], data[cols[2]]
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
class FileReaderNPZ(FileReaderArray):
|
|
286
|
+
_extension: str = ".npz"
|
|
287
|
+
|
|
288
|
+
def __init__(self, file_name: str | Path) -> None:
|
|
289
|
+
super().__init__(file_name)
|
|
290
|
+
from numpy import load
|
|
291
|
+
|
|
292
|
+
self._file = load(self._file_name, allow_pickle=True)
|
|
293
|
+
|
|
294
|
+
def _close(self) -> None:
|
|
295
|
+
super()._close()
|
|
296
|
+
del self._file
|
|
297
|
+
|
|
298
|
+
def _get_object_impl(self, object_name: str, **kwargs) -> Any:
|
|
299
|
+
assert not kwargs
|
|
300
|
+
return self._file[object_name]
|
|
301
|
+
|
|
302
|
+
def keys(self) -> tuple[str, ...]:
|
|
303
|
+
return tuple(self._file.keys())
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class FileReaderHDF5(FileReaderArray):
|
|
307
|
+
_extension: str = ".hdf5"
|
|
308
|
+
|
|
309
|
+
def __init__(self, file_name: str | Path) -> None:
|
|
310
|
+
super().__init__(file_name)
|
|
311
|
+
from h5py import File
|
|
312
|
+
|
|
313
|
+
self._file = File(self._file_name, "r")
|
|
314
|
+
|
|
315
|
+
def _close(self) -> None:
|
|
316
|
+
super()._close()
|
|
317
|
+
self._file.close()
|
|
318
|
+
|
|
319
|
+
def _get_object_impl(self, object_name: str, **kwargs) -> Any:
|
|
320
|
+
assert not kwargs
|
|
321
|
+
return self._file[object_name]
|
|
322
|
+
|
|
323
|
+
def _get_array(self, object_name: str) -> NDArray:
|
|
324
|
+
ret = self._get_object(object_name)
|
|
325
|
+
return ret[:]
|
|
326
|
+
|
|
327
|
+
def keys(self) -> tuple[str, ...]:
|
|
328
|
+
return tuple(self._file.keys())
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
class FileReaderTSV(FileReaderArray):
|
|
332
|
+
_extension: str = ".tsv"
|
|
333
|
+
|
|
334
|
+
def __init__(self, file_name: str | Path) -> None:
|
|
335
|
+
super().__init__(file_name)
|
|
336
|
+
|
|
337
|
+
def _get_filenames(self, object_name: str) -> tuple[str, ...]:
|
|
338
|
+
uncompressed = (
|
|
339
|
+
str(self._file_name / f"{object_name}{self._extension}"),
|
|
340
|
+
f"{self._file_name.parent/self._file_name.stem}_{object_name}{self._extension}",
|
|
341
|
+
str(self._file_name / f"{self._file_name.stem}_{object_name}{self._extension}"),
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
return uncompressed + tuple(f"{fname}.bz2" for fname in uncompressed)
|
|
345
|
+
|
|
346
|
+
def _get_object_impl(self, object_name: str, return_record: bool = True) -> Any:
|
|
347
|
+
filenames = self._get_filenames(object_name)
|
|
348
|
+
|
|
349
|
+
if return_record:
|
|
350
|
+
from pandas import read_table
|
|
351
|
+
|
|
352
|
+
for filename in filenames:
|
|
353
|
+
with suppress(FileNotFoundError):
|
|
354
|
+
df = read_table(filename, comment="#", sep=None, engine="python")
|
|
355
|
+
logger.log(INFO1, f"Read: {filename}")
|
|
356
|
+
return df.to_records(index=False)
|
|
357
|
+
else:
|
|
358
|
+
from numpy import loadtxt
|
|
359
|
+
|
|
360
|
+
for filename in filenames:
|
|
361
|
+
with suppress(FileNotFoundError):
|
|
362
|
+
ret = loadtxt(filename)
|
|
363
|
+
logger.log(INFO1, f"Read: {filename}")
|
|
364
|
+
return ret
|
|
365
|
+
|
|
366
|
+
raise FileNotFoundError(", ".join(map(str, filenames)))
|
|
367
|
+
|
|
368
|
+
def _get_array(self, object_name: str) -> NDArray:
|
|
369
|
+
return self._get_object(object_name, return_record=False)
|
|
370
|
+
|
|
371
|
+
def keys(self) -> tuple[str, ...]:
|
|
372
|
+
return tuple(file for file in listdir(self._file_name) if file.endswith(self._extension))
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class FileReaderROOTUpROOT(FileReader):
|
|
376
|
+
_extension: str = ".root"
|
|
377
|
+
|
|
378
|
+
def __init__(self, file_name: str | Path) -> None:
|
|
379
|
+
super().__init__(file_name)
|
|
380
|
+
from uproot import open
|
|
381
|
+
|
|
382
|
+
self._file = open(file_name)
|
|
383
|
+
|
|
384
|
+
def _close(self) -> None:
|
|
385
|
+
super()._close()
|
|
386
|
+
self._file.close()
|
|
387
|
+
|
|
388
|
+
def _get_object_impl(self, object_name: str, **kwargs) -> Any:
|
|
389
|
+
assert not kwargs
|
|
390
|
+
return self._file[object_name]
|
|
391
|
+
|
|
392
|
+
def _get_hist(self, object_name: str) -> tuple[NDArray, NDArray]:
|
|
393
|
+
obj = self._get_object(object_name)
|
|
394
|
+
y, x = obj.to_numpy()
|
|
395
|
+
return x, y
|
|
396
|
+
|
|
397
|
+
def _get_graph(self, object_name: str) -> tuple[NDArray, NDArray]:
|
|
398
|
+
obj = self._get_object(object_name)
|
|
399
|
+
y, x = obj.to_numpy()
|
|
400
|
+
return x[:-1], y
|
|
401
|
+
|
|
402
|
+
def _get_array(self, object_name: str) -> NDArray:
|
|
403
|
+
obj = self._get_object(object_name)
|
|
404
|
+
y, _ = obj.to_numpy()
|
|
405
|
+
return y
|
|
406
|
+
|
|
407
|
+
def _get_record(self, object_name: str) -> dict[str, NDArray]:
|
|
408
|
+
tree = self._get_object(object_name)
|
|
409
|
+
return {key: tree[key].array().to_numpy().copy() for key in tree.keys()}
|
|
410
|
+
|
|
411
|
+
def keys(self) -> tuple[str, ...]:
|
|
412
|
+
return tuple(key.split(";", 1)[0] for key in self._file.GetListOfKeys())
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
with suppress(ImportError):
|
|
416
|
+
import ROOT
|
|
417
|
+
|
|
418
|
+
class FileReaderROOTROOT(FileReader):
|
|
419
|
+
_extension: str = ".root"
|
|
420
|
+
_reader_uproot: FileReaderROOTUpROOT | None = None
|
|
421
|
+
|
|
422
|
+
def __init__(self, file_name: str | Path) -> None:
|
|
423
|
+
super().__init__(file_name)
|
|
424
|
+
from ROOT import TFile
|
|
425
|
+
|
|
426
|
+
self._file = TFile(file_name)
|
|
427
|
+
if self._file.IsZombie():
|
|
428
|
+
raise FileNotFoundError(file_name)
|
|
429
|
+
|
|
430
|
+
@property
|
|
431
|
+
def reader_uproot(self) -> FileReaderROOTUpROOT:
|
|
432
|
+
if self._reader_uproot is None:
|
|
433
|
+
self._reader_uproot = FileReaderROOTUpROOT(self._file_name)
|
|
434
|
+
|
|
435
|
+
return self._reader_uproot
|
|
436
|
+
|
|
437
|
+
def _close(self) -> None:
|
|
438
|
+
super()._close()
|
|
439
|
+
self._file.Close()
|
|
440
|
+
|
|
441
|
+
if self._reader_uproot is not None:
|
|
442
|
+
self._reader_uproot._close()
|
|
443
|
+
|
|
444
|
+
def _get_object_impl(self, object_name: str, **kwargs) -> Any:
|
|
445
|
+
assert not kwargs
|
|
446
|
+
ret = self._file.Get(object_name)
|
|
447
|
+
if not ret:
|
|
448
|
+
raise KeyError(object_name)
|
|
449
|
+
return ret
|
|
450
|
+
|
|
451
|
+
def _get_hist(self, object_name: str) -> tuple[NDArray, NDArray]:
|
|
452
|
+
import ROOT
|
|
453
|
+
|
|
454
|
+
obj = self._get_object(object_name)
|
|
455
|
+
if isinstance(obj, ROOT.TH1) and obj.GetDimension() == 1:
|
|
456
|
+
return _get_bin_edges(obj.GetXaxis()), _get_buffer_hist1(obj, flows=False)
|
|
457
|
+
|
|
458
|
+
raise ValueError(f"Do not know ho to convert {obj} to hist")
|
|
459
|
+
|
|
460
|
+
def _get_graph(self, object_name: str) -> tuple[NDArray, NDArray]:
|
|
461
|
+
import ROOT
|
|
462
|
+
|
|
463
|
+
obj = self._get_object(object_name)
|
|
464
|
+
if isinstance(obj, ROOT.TH1) and obj.GetDimension() == 1:
|
|
465
|
+
return _get_bin_left_edges(obj.GetXaxis()), _get_buffer_hist1(obj, flows=False)
|
|
466
|
+
if isinstance(obj, ROOT.TGraph):
|
|
467
|
+
return _get_buffers_graph(obj)
|
|
468
|
+
|
|
469
|
+
raise ValueError(f"Do not know ho to convert {obj} to graph")
|
|
470
|
+
|
|
471
|
+
def _get_array(self, object_name: str) -> NDArray:
|
|
472
|
+
import ROOT
|
|
473
|
+
|
|
474
|
+
obj = self._get_object(object_name)
|
|
475
|
+
|
|
476
|
+
if isinstance(obj, ROOT.TH1) and obj.GetDimension() == 1:
|
|
477
|
+
return _get_buffer_hist1(obj)
|
|
478
|
+
if isinstance(obj, ROOT.TH2) and obj.GetDimension() == 2:
|
|
479
|
+
return _get_buffer_hist2(obj)
|
|
480
|
+
if isinstance(obj, (ROOT.TMatrixD, ROOT.TMatrixF)):
|
|
481
|
+
return _get_buffer_matrix(obj)
|
|
482
|
+
|
|
483
|
+
raise ValueError(f"Do not know ho to convert {obj} to array")
|
|
484
|
+
|
|
485
|
+
def _get_record(self, object_name: str) -> dict[str, NDArray]:
|
|
486
|
+
return self.reader_uproot.get_record(object_name)
|
|
487
|
+
|
|
488
|
+
def keys(self) -> tuple[str, ...]:
|
|
489
|
+
return tuple(key.GetName().split(";", 1)[0] for key in self._file.GetListOfKeys())
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
def iterate_filenames(
|
|
493
|
+
filenames: Sequence[str | Path], keys: Sequence[KeyLike]
|
|
494
|
+
) -> Generator[tuple[TupleKey, str | Path], None, None]:
|
|
495
|
+
for keylike in keys:
|
|
496
|
+
key = properkey(keylike)
|
|
497
|
+
for afilename in filenames:
|
|
498
|
+
filename = str(afilename)
|
|
499
|
+
if "{" in filename:
|
|
500
|
+
ffilename = filename.format(*key)
|
|
501
|
+
yield key, ffilename
|
|
502
|
+
break
|
|
503
|
+
elif all(map(filename.__contains__, key)):
|
|
504
|
+
yield key, afilename
|
|
505
|
+
break
|
|
506
|
+
else:
|
|
507
|
+
raise RuntimeError(f"Could not find a file for key {'.'.join(key)}")
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
def iterate_filenames_and_objectnames(
|
|
511
|
+
filenames: Sequence[str | Path],
|
|
512
|
+
filename_keys: Sequence[KeyLike],
|
|
513
|
+
keys: Sequence[KeyLike],
|
|
514
|
+
*,
|
|
515
|
+
skip: Sequence[set[str]] | None = None,
|
|
516
|
+
key_order: Sequence[int] | None = None,
|
|
517
|
+
) -> Generator[tuple[TupleKey, str | Path, TupleKey, TupleKey], None, None]:
|
|
518
|
+
reorder_key = make_reorder_function(key_order)
|
|
519
|
+
for filekey, filename in iterate_filenames(filenames, filename_keys):
|
|
520
|
+
for key in keys:
|
|
521
|
+
key = properkey(key)
|
|
522
|
+
fullkey = filekey + key
|
|
523
|
+
if skip is not None and any(skipkey.issubset(fullkey) for skipkey in skip):
|
|
524
|
+
continue
|
|
525
|
+
fullkey = reorder_key(fullkey)
|
|
526
|
+
yield filekey, filename, key, fullkey
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
def _get_buffer_hist1(h: ROOT.TH1, flows: bool = False) -> NDArray:
|
|
530
|
+
"""Return TH1* histogram data buffer if flows=False, exclude underflow and
|
|
531
|
+
overflow."""
|
|
532
|
+
buf = h.GetArray()
|
|
533
|
+
buf = frombuffer(buf, dtype(buf.typecode), h.GetNbinsX() + 2)
|
|
534
|
+
if not flows:
|
|
535
|
+
buf = buf[1:-1]
|
|
536
|
+
|
|
537
|
+
return buf.copy()
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
def _get_buffer_hist2(h, flows=False):
|
|
541
|
+
"""Return histogram data buffer
|
|
542
|
+
if flows=False, exclude underflow and overflow
|
|
543
|
+
NOTE: buf[biny][binx] is the right access signature
|
|
544
|
+
"""
|
|
545
|
+
nx, ny = h.GetNbinsX(), h.GetNbinsY()
|
|
546
|
+
buf = h.GetArray()
|
|
547
|
+
res = frombuffer(buf, dtype(buf.typecode), (nx + 2) * (ny + 2)).reshape((ny + 2, nx + 2))
|
|
548
|
+
if not flows:
|
|
549
|
+
res = res[1 : ny + 1, 1 : nx + 1]
|
|
550
|
+
|
|
551
|
+
return res.copy()
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
def _get_bin_edges(ax: ROOT.TAxis) -> NDArray:
|
|
555
|
+
"""Get the array with bin edges."""
|
|
556
|
+
xbins = ax.GetXbins()
|
|
557
|
+
n = xbins.GetSize()
|
|
558
|
+
if n > 0:
|
|
559
|
+
lims = frombuffer(xbins.GetArray(), double, n)
|
|
560
|
+
return lims.copy()
|
|
561
|
+
return linspace(ax.GetXmin(), ax.GetXmax(), ax.GetNbins() + 1)
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def _get_bin_left_edges(ax: ROOT.TAxis) -> NDArray:
|
|
565
|
+
"""Get the array with bin left edges."""
|
|
566
|
+
xbins = ax.GetXbins()
|
|
567
|
+
n = xbins.GetSize()
|
|
568
|
+
if n > 0:
|
|
569
|
+
lims = frombuffer(xbins.GetArray(), double, n)
|
|
570
|
+
return lims[:-1].copy()
|
|
571
|
+
return linspace(ax.GetXmin(), ax.GetXmax(), ax.GetNbins() + 1)[:-1]
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def _get_buffers_graph(g: ROOT.TGraph) -> tuple[NDArray, NDArray]:
|
|
575
|
+
"""Get TGraph x and y buffers."""
|
|
576
|
+
npoints = g.GetN()
|
|
577
|
+
if npoints == 0:
|
|
578
|
+
raise RuntimeError("Got graph with 0 points")
|
|
579
|
+
|
|
580
|
+
return (
|
|
581
|
+
frombuffer(g.GetX(), dtype=double, count=npoints).copy(),
|
|
582
|
+
frombuffer(g.GetY(), dtype=double, count=npoints).copy(),
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
def _get_buffer_matrix(m):
|
|
587
|
+
"""Get TMatrix buffer."""
|
|
588
|
+
cbuf = m.GetMatrixArray()
|
|
589
|
+
res = frombuffer(cbuf, dtype(cbuf.typecode), m.GetNoElements()).reshape(
|
|
590
|
+
m.GetNrows(), m.GetNcols()
|
|
591
|
+
)
|
|
592
|
+
return res.astype(double).copy()
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from collections.abc import Callable, Mapping
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from numpy import asarray
|
|
5
|
+
from schema import And, Optional, Or, Schema, Use
|
|
6
|
+
|
|
7
|
+
from nested_mapping.tools.map import make_reorder_function
|
|
8
|
+
from nested_mapping.typing import strkey
|
|
9
|
+
|
|
10
|
+
from ..core.storage import NodeStorage
|
|
11
|
+
from ..lib.common import Array
|
|
12
|
+
from ..tools.logger import INFO3, logger
|
|
13
|
+
from ..tools.schema import (
|
|
14
|
+
AllFileswithExt,
|
|
15
|
+
IsFilenameSeqOrFilename,
|
|
16
|
+
IsStrSeqOrStr,
|
|
17
|
+
LoadFileWithExt,
|
|
18
|
+
LoadYaml,
|
|
19
|
+
)
|
|
20
|
+
from .file_reader import FileReader, file_readers, iterate_filenames_and_objectnames
|
|
21
|
+
|
|
22
|
+
_schema_cfg = Schema(
|
|
23
|
+
{
|
|
24
|
+
"name": str,
|
|
25
|
+
"filenames": And(IsFilenameSeqOrFilename, AllFileswithExt(*file_readers.keys())),
|
|
26
|
+
Optional("dtype", default=None): Or("d", "f"),
|
|
27
|
+
Optional("replicate_outputs", default=((),)): Or((IsStrSeqOrStr,), [IsStrSeqOrStr]),
|
|
28
|
+
Optional("replicate_files", default=((),)): Or((IsStrSeqOrStr,), [IsStrSeqOrStr]),
|
|
29
|
+
Optional("skip", default=None): And(
|
|
30
|
+
Or(((str,),), [[str]]), Use(lambda l: tuple(set(k) for k in l))
|
|
31
|
+
),
|
|
32
|
+
Optional("key_order", default=None): Or(
|
|
33
|
+
((str,), (str,)),
|
|
34
|
+
[[str], [str]],
|
|
35
|
+
(int,),
|
|
36
|
+
[int],
|
|
37
|
+
),
|
|
38
|
+
Optional("output_key_order", default=None): Or(
|
|
39
|
+
((str,), (str,)),
|
|
40
|
+
[[str], [str]],
|
|
41
|
+
(int,),
|
|
42
|
+
[int],
|
|
43
|
+
),
|
|
44
|
+
Optional("name_function", default=lambda: lambda st, tpl: st): Or(
|
|
45
|
+
Callable, And({str: str}, Use(lambda dct: lambda st, tpl: dct.get(st, st)))
|
|
46
|
+
),
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
_schema_loadable_cfg = And(
|
|
51
|
+
{"load": Or(str, And(Path, Use(str))), Optional(str): object},
|
|
52
|
+
Use(
|
|
53
|
+
LoadFileWithExt(yaml=LoadYaml, key="load", update=True),
|
|
54
|
+
error="Failed to load {}",
|
|
55
|
+
),
|
|
56
|
+
_schema_cfg,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _validate_cfg(cfg):
|
|
61
|
+
if isinstance(cfg, dict) and "load" in cfg:
|
|
62
|
+
return _schema_loadable_cfg.validate(cfg)
|
|
63
|
+
else:
|
|
64
|
+
return _schema_cfg.validate(cfg)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def load_array(acfg: Mapping | None = None, *, array_kwargs: Mapping = {}, **kwargs) -> NodeStorage:
|
|
68
|
+
acfg = dict(acfg or {}, **kwargs)
|
|
69
|
+
cfg = _validate_cfg(acfg)
|
|
70
|
+
|
|
71
|
+
name = (cfg["name"],)
|
|
72
|
+
filenames = cfg["filenames"]
|
|
73
|
+
keys = cfg["replicate_outputs"]
|
|
74
|
+
file_keys = cfg["replicate_files"]
|
|
75
|
+
name_function = cfg["name_function"]
|
|
76
|
+
skip = cfg["skip"]
|
|
77
|
+
key_order = cfg["key_order"]
|
|
78
|
+
output_key_order = cfg["output_key_order"]
|
|
79
|
+
dtype = cfg["dtype"]
|
|
80
|
+
|
|
81
|
+
data = {}
|
|
82
|
+
reorder_output_key = make_reorder_function(output_key_order)
|
|
83
|
+
for _, filename, _, key in iterate_filenames_and_objectnames(
|
|
84
|
+
filenames, file_keys, keys, skip=skip, key_order=key_order
|
|
85
|
+
):
|
|
86
|
+
skey = strkey(key)
|
|
87
|
+
logger.log(INFO3, f"Process {skey}")
|
|
88
|
+
|
|
89
|
+
array = FileReader.array[filename, name_function(skey, key)]
|
|
90
|
+
output_key = reorder_output_key(key)
|
|
91
|
+
data[output_key] = asarray(array, dtype)
|
|
92
|
+
|
|
93
|
+
storage = NodeStorage(default_containers=True)
|
|
94
|
+
with storage:
|
|
95
|
+
for key, array in data.items():
|
|
96
|
+
Array.replicate(name=".".join(name + key), array=array, **array_kwargs)
|
|
97
|
+
|
|
98
|
+
NodeStorage.update_current(storage, strict=True)
|
|
99
|
+
|
|
100
|
+
return storage
|