f9columnar 0.3.0__tar.gz → 0.3.2__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.
- {f9columnar-0.3.0 → f9columnar-0.3.2}/PKG-INFO +1 -1
- f9columnar-0.3.2/f9columnar/hdf5_writer.py +326 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/ml/dataloader_helpers.py +6 -1
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/ml/dataset_scaling.py +1 -1
- f9columnar-0.3.0/f9columnar/ml/hdf5_writer_processor.py → f9columnar-0.3.2/f9columnar/ml/hdf5_parallel_writer.py +5 -2
- f9columnar-0.3.0/f9columnar/ml/hdf5_writer_postprocessor.py → f9columnar-0.3.2/f9columnar/ml/hdf5_writer.py +3 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/root_dataloader.py +45 -10
- {f9columnar-0.3.0 → f9columnar-0.3.2}/pyproject.toml +1 -1
- {f9columnar-0.3.0 → f9columnar-0.3.2}/LICENSE +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/README.md +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/__init__.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/arrays.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/data/PMGxsecDB_mc16.txt +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/data/PMGxsecDB_mc21.txt +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/data/campaigns.json +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/data/luminosity.json +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/data/periods.json +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/data/truth_classification.json +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/dataset_builder.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/hdf5_dataloader.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/histograms.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/ml/__init__.py +0 -0
- /f9columnar-0.3.0/f9columnar/ml/hdf5_ml_dataloader.py → /f9columnar-0.3.2/f9columnar/ml/hdf5_dataloader.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/ml/imbalanced_sampler.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/ml/scalers.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/processors.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/processors_collection.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/run.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/submit/__init__.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/submit/act_driver.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/submit/act_handler.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/submit/act_merger.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/submit/act_run.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/submit/act_run.sh +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/__init__.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/ak_helpers.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/config_utils.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/helpers.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/loggers.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/regex_helpers.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/rucio_db.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/rucio_utils.py +0 -0
- {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/xsec_db.py +0 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
from abc import abstractmethod
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import awkward as ak
|
|
9
|
+
import h5py
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
from f9columnar.processors import Postprocessor, Processor
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BaseArraysHdf5Writer(Postprocessor):
|
|
16
|
+
def __init__(self, file_path: str, dataset_names: str | list[str] | None = None, name: str = "HDF5Writer") -> None:
|
|
17
|
+
"""Class for HDF5 data writer postprocessors that write awkward arrays to HDF5 file.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
file_path : str
|
|
22
|
+
Path to the created HDF5 file.
|
|
23
|
+
dataset_names : str | list[str] | None, optional
|
|
24
|
+
Names of the datasets to be created. Can be dir/subdir/.../dataset_name.
|
|
25
|
+
name : str, optional
|
|
26
|
+
Name of the processor.
|
|
27
|
+
|
|
28
|
+
Other Parameters
|
|
29
|
+
----------------
|
|
30
|
+
shape, chunks, maxshape, dtype, compression, compression_opts
|
|
31
|
+
See [1].
|
|
32
|
+
|
|
33
|
+
References
|
|
34
|
+
----------
|
|
35
|
+
[1] - https://docs.h5py.org/en/stable/high/group.html#h5py.Group.create_dataset
|
|
36
|
+
[2] - https://docs.h5py.org/en/stable/high/dataset.html
|
|
37
|
+
[3] - https://pythonforthelab.com/blog/how-to-use-hdf5-files-in-python/
|
|
38
|
+
|
|
39
|
+
"""
|
|
40
|
+
super().__init__(name)
|
|
41
|
+
self.file_path = file_path
|
|
42
|
+
|
|
43
|
+
if type(dataset_names) is str:
|
|
44
|
+
self.dataset_names = [dataset_names]
|
|
45
|
+
elif type(dataset_names) is list:
|
|
46
|
+
self.dataset_names = dataset_names
|
|
47
|
+
else:
|
|
48
|
+
self.dataset_names = []
|
|
49
|
+
|
|
50
|
+
self._current_idx = 0
|
|
51
|
+
self._current_shape: int | None = None
|
|
52
|
+
|
|
53
|
+
def create_datasets(
|
|
54
|
+
self,
|
|
55
|
+
mode: str = "w",
|
|
56
|
+
dataset_names: list[str] | None = None,
|
|
57
|
+
shape: tuple[int, int] | tuple[int, int, int] | None = None,
|
|
58
|
+
chunks: bool = False,
|
|
59
|
+
maxshape: tuple[int | None, int] | tuple[int | None, int, int] | None = None,
|
|
60
|
+
dtype: str = "float32",
|
|
61
|
+
compression: str = "lzf",
|
|
62
|
+
compression_opts: int | None = None,
|
|
63
|
+
) -> None:
|
|
64
|
+
if mode not in ["w", "a"]:
|
|
65
|
+
raise ValueError("Mode must be 'w' or 'a'!")
|
|
66
|
+
|
|
67
|
+
if maxshape is not None and shape is None:
|
|
68
|
+
raise ValueError("Shape must be provided if maxshape is provided!")
|
|
69
|
+
|
|
70
|
+
if maxshape is not None or compression:
|
|
71
|
+
logging.info("Auto-chunking is enabled by default, if you use compression or maxshape.")
|
|
72
|
+
chunks = True
|
|
73
|
+
|
|
74
|
+
if dataset_names is None:
|
|
75
|
+
dataset_names = self.dataset_names
|
|
76
|
+
|
|
77
|
+
if len(dataset_names) == 0:
|
|
78
|
+
raise ValueError("No dataset names provided!")
|
|
79
|
+
|
|
80
|
+
with h5py.File(self.file_path, mode) as f:
|
|
81
|
+
for dataset_name in dataset_names:
|
|
82
|
+
dataset_name_split = dataset_name.split("/")
|
|
83
|
+
|
|
84
|
+
f_obj = f
|
|
85
|
+
for i, group in enumerate(dataset_name_split):
|
|
86
|
+
if i == len(dataset_name_split) - 1:
|
|
87
|
+
f_obj.create_dataset(
|
|
88
|
+
group,
|
|
89
|
+
shape=shape,
|
|
90
|
+
chunks=chunks,
|
|
91
|
+
maxshape=maxshape,
|
|
92
|
+
dtype=dtype,
|
|
93
|
+
compression=compression,
|
|
94
|
+
compression_opts=compression_opts,
|
|
95
|
+
)
|
|
96
|
+
elif i == 0:
|
|
97
|
+
if group not in f_obj:
|
|
98
|
+
g = f.create_group(group)
|
|
99
|
+
f_obj = g
|
|
100
|
+
else:
|
|
101
|
+
f_obj = f_obj[group]
|
|
102
|
+
else:
|
|
103
|
+
g = g.create_group(group)
|
|
104
|
+
f_obj = g
|
|
105
|
+
|
|
106
|
+
def add_data(
|
|
107
|
+
self,
|
|
108
|
+
data: np.ndarray,
|
|
109
|
+
dataset_name: str,
|
|
110
|
+
idx: int | tuple[int, int],
|
|
111
|
+
resize: tuple | None = None,
|
|
112
|
+
) -> None:
|
|
113
|
+
if type(idx) is tuple and len(idx) > 2:
|
|
114
|
+
raise ValueError("Only support 2D data!")
|
|
115
|
+
|
|
116
|
+
with h5py.File(self.file_path, "a") as f:
|
|
117
|
+
dataset = f[dataset_name]
|
|
118
|
+
|
|
119
|
+
if resize:
|
|
120
|
+
dataset.resize(resize)
|
|
121
|
+
|
|
122
|
+
if type(idx) is int:
|
|
123
|
+
dataset[idx] = data
|
|
124
|
+
elif type(idx) is tuple:
|
|
125
|
+
dataset[idx[0] : idx[1]] = data
|
|
126
|
+
else:
|
|
127
|
+
raise TypeError("idx must be a tuple or an integer!")
|
|
128
|
+
|
|
129
|
+
def add_metadata(self, metadata_dct: dict[str, Any], group_name: str | None = None) -> None:
|
|
130
|
+
with h5py.File(self.file_path, "a") as f:
|
|
131
|
+
if group_name is not None:
|
|
132
|
+
group = f[group_name]
|
|
133
|
+
else:
|
|
134
|
+
group = f
|
|
135
|
+
|
|
136
|
+
group.create_dataset("metadata", data=json.dumps(metadata_dct))
|
|
137
|
+
|
|
138
|
+
def get_metadata(self, group_name: str | None = None) -> dict[str, Any]:
|
|
139
|
+
if group_name is None:
|
|
140
|
+
group_name = "metadata"
|
|
141
|
+
else:
|
|
142
|
+
group_name = f"{group_name}/metadata"
|
|
143
|
+
|
|
144
|
+
with h5py.File(self.file_path, "r") as f:
|
|
145
|
+
metadata = json.loads(f[group_name][()])
|
|
146
|
+
|
|
147
|
+
return metadata
|
|
148
|
+
|
|
149
|
+
def get_keys(self) -> list[str]:
|
|
150
|
+
with h5py.File(self.file_path, "r") as f:
|
|
151
|
+
keys = list(f.keys())
|
|
152
|
+
|
|
153
|
+
return keys
|
|
154
|
+
|
|
155
|
+
def get_handle(self, mode: str = "r") -> h5py.File:
|
|
156
|
+
return h5py.File(self.file_path, mode)
|
|
157
|
+
|
|
158
|
+
def write_arrays(
|
|
159
|
+
self,
|
|
160
|
+
arrays: ak.Array,
|
|
161
|
+
dataset_name: str,
|
|
162
|
+
column_names: list[str],
|
|
163
|
+
chunk_shape: int = 1000,
|
|
164
|
+
) -> None:
|
|
165
|
+
if self._current_shape is None:
|
|
166
|
+
self._current_shape = chunk_shape
|
|
167
|
+
|
|
168
|
+
save_arrays = []
|
|
169
|
+
|
|
170
|
+
for column_name in column_names:
|
|
171
|
+
if column_name not in arrays.fields:
|
|
172
|
+
raise RuntimeError(f"Column {column_name} not found in arrays!")
|
|
173
|
+
|
|
174
|
+
column = ak.to_numpy(arrays[column_name])
|
|
175
|
+
column = column[:, None]
|
|
176
|
+
save_arrays.append(column)
|
|
177
|
+
|
|
178
|
+
save_arrays = np.concatenate(save_arrays, axis=1)
|
|
179
|
+
|
|
180
|
+
array_chunks = len(save_arrays) // chunk_shape + 1
|
|
181
|
+
chunk_save_arrays = np.array_split(save_arrays, array_chunks)
|
|
182
|
+
|
|
183
|
+
for chunk_array in chunk_save_arrays:
|
|
184
|
+
n_chunk = len(chunk_array)
|
|
185
|
+
start_idx, stop_idx = self._current_idx, self._current_idx + n_chunk
|
|
186
|
+
|
|
187
|
+
self._current_idx = stop_idx
|
|
188
|
+
|
|
189
|
+
if self._current_idx > self._current_shape:
|
|
190
|
+
resize = (stop_idx, chunk_array.shape[1])
|
|
191
|
+
self._current_shape = stop_idx
|
|
192
|
+
else:
|
|
193
|
+
resize = None
|
|
194
|
+
|
|
195
|
+
self.add_data(chunk_array, dataset_name, idx=(start_idx, stop_idx), resize=resize)
|
|
196
|
+
|
|
197
|
+
@abstractmethod
|
|
198
|
+
def run(self, processors: dict[str, Processor], *args: Any, **kwargs: Any):
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class DatasetHdf5Writer(BaseArraysHdf5Writer):
|
|
203
|
+
def __init__(
|
|
204
|
+
self,
|
|
205
|
+
file_path: str,
|
|
206
|
+
dataset_name: str,
|
|
207
|
+
column_names: list[str],
|
|
208
|
+
save_node: str = "output",
|
|
209
|
+
chunk_shape: int = 1000,
|
|
210
|
+
name: str = "datasetHDF5Writer",
|
|
211
|
+
**hdf5_kwargs: Any,
|
|
212
|
+
) -> None:
|
|
213
|
+
super().__init__(file_path, dataset_names=dataset_name, name=name)
|
|
214
|
+
self.chunk_shape = chunk_shape
|
|
215
|
+
self.column_names = column_names
|
|
216
|
+
self.save_node = save_node
|
|
217
|
+
|
|
218
|
+
self.create_datasets(
|
|
219
|
+
shape=(chunk_shape, len(column_names)),
|
|
220
|
+
maxshape=(None, len(column_names)),
|
|
221
|
+
**hdf5_kwargs,
|
|
222
|
+
)
|
|
223
|
+
self.add_metadata({"columns": self.column_names})
|
|
224
|
+
|
|
225
|
+
def run(self, processors: dict[str, Processor]) -> dict[str, dict[str, Processor]]:
|
|
226
|
+
arrays_processor = processors[self.save_node]
|
|
227
|
+
|
|
228
|
+
if hasattr(arrays_processor, "arrays"):
|
|
229
|
+
arrays = arrays_processor.arrays
|
|
230
|
+
else:
|
|
231
|
+
raise AttributeError("Arrays attribute not found in the processor!")
|
|
232
|
+
|
|
233
|
+
if len(arrays) == 0:
|
|
234
|
+
return {"processors": processors}
|
|
235
|
+
|
|
236
|
+
self.write_arrays(arrays, self.dataset_names[0], self.column_names, self.chunk_shape)
|
|
237
|
+
|
|
238
|
+
return {"processors": processors}
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class NtupleHdf5Writer(BaseArraysHdf5Writer):
|
|
242
|
+
def __init__(
|
|
243
|
+
self,
|
|
244
|
+
file_path: str,
|
|
245
|
+
mc_column_names: list[str],
|
|
246
|
+
data_column_names: list[str] | None = None,
|
|
247
|
+
save_node: str = "output",
|
|
248
|
+
chunk_shape: int = 1000,
|
|
249
|
+
write_mc: bool = True,
|
|
250
|
+
write_data: bool = True,
|
|
251
|
+
name: str = "datasetHDF5Writer",
|
|
252
|
+
dataset_names: list[str] | None = None,
|
|
253
|
+
**hdf5_kwargs: Any,
|
|
254
|
+
) -> None:
|
|
255
|
+
if dataset_names is None:
|
|
256
|
+
dataset_names = ["mc", "data"]
|
|
257
|
+
|
|
258
|
+
if len(dataset_names) != 2:
|
|
259
|
+
raise ValueError("Dataset names must be a list of two strings!")
|
|
260
|
+
|
|
261
|
+
super().__init__(file_path, dataset_names=dataset_names, name=name)
|
|
262
|
+
self.save_node = save_node
|
|
263
|
+
self.chunk_shape = chunk_shape
|
|
264
|
+
|
|
265
|
+
if write_data is False and write_mc is False:
|
|
266
|
+
raise ValueError("Both write_data and write_mc cannot be False!")
|
|
267
|
+
|
|
268
|
+
self.write_data, self.write_mc = write_data, write_mc
|
|
269
|
+
|
|
270
|
+
self.mc_column_names = mc_column_names
|
|
271
|
+
|
|
272
|
+
if data_column_names is None:
|
|
273
|
+
logging.info("Data column names not provided, using MC column names.")
|
|
274
|
+
self.data_column_names = mc_column_names
|
|
275
|
+
else:
|
|
276
|
+
self.data_column_names = data_column_names
|
|
277
|
+
|
|
278
|
+
metadata = {}
|
|
279
|
+
mc_group, data_group = self.dataset_names[0], self.dataset_names[1]
|
|
280
|
+
|
|
281
|
+
if write_mc:
|
|
282
|
+
self.create_datasets(
|
|
283
|
+
dataset_names=[mc_group],
|
|
284
|
+
shape=(self.chunk_shape, len(self.mc_column_names)),
|
|
285
|
+
maxshape=(None, len(self.mc_column_names)),
|
|
286
|
+
**hdf5_kwargs,
|
|
287
|
+
)
|
|
288
|
+
metadata[f"{mc_group}_columns"] = self.mc_column_names
|
|
289
|
+
|
|
290
|
+
if write_data:
|
|
291
|
+
self.create_datasets(
|
|
292
|
+
mode="a" if self.write_mc else "w",
|
|
293
|
+
dataset_names=[data_group],
|
|
294
|
+
shape=(self.chunk_shape, len(self.data_column_names)),
|
|
295
|
+
maxshape=(None, len(self.data_column_names)),
|
|
296
|
+
**hdf5_kwargs,
|
|
297
|
+
)
|
|
298
|
+
metadata[f"{data_group}_columns"] = self.data_column_names
|
|
299
|
+
|
|
300
|
+
self.add_metadata(metadata)
|
|
301
|
+
|
|
302
|
+
self._current_mc_idx, self._current_data_idx = 0, 0
|
|
303
|
+
self._current_mc_shape, self._current_data_shape = None, None
|
|
304
|
+
|
|
305
|
+
def run(self, processors: dict[str, Processor]) -> dict[str, dict[str, Processor]]:
|
|
306
|
+
arrays_processor = processors[self.save_node]
|
|
307
|
+
|
|
308
|
+
if hasattr(arrays_processor, "arrays"):
|
|
309
|
+
arrays = arrays_processor.arrays
|
|
310
|
+
else:
|
|
311
|
+
raise AttributeError("Arrays attribute not found in the processor!")
|
|
312
|
+
|
|
313
|
+
if len(arrays) == 0:
|
|
314
|
+
return {"processors": processors}
|
|
315
|
+
|
|
316
|
+
if self.is_data and self.write_data:
|
|
317
|
+
self._current_idx, self._current_shape = self._current_mc_idx, self._current_mc_shape
|
|
318
|
+
self.write_arrays(arrays, self.dataset_names[1], self.data_column_names, self.chunk_shape)
|
|
319
|
+
self._current_mc_idx, self._current_mc_shape = self._current_idx, self._current_shape
|
|
320
|
+
|
|
321
|
+
if not self.is_data and self.write_mc:
|
|
322
|
+
self._current_idx, self._current_shape = self._current_data_idx, self._current_data_shape
|
|
323
|
+
self.write_arrays(arrays, self.dataset_names[0], self.mc_column_names, self.chunk_shape)
|
|
324
|
+
self._current_data_idx, self._current_data_shape = self._current_idx, self._current_shape
|
|
325
|
+
|
|
326
|
+
return {"processors": processors}
|
|
@@ -377,6 +377,11 @@ def get_column_selection(hdf5_files: str | list[str], column_names: list[str]) -
|
|
|
377
377
|
selection = ColumnSelection()
|
|
378
378
|
|
|
379
379
|
for dataset_name in used_columns_dct.keys():
|
|
380
|
+
if dataset_name in pad_values:
|
|
381
|
+
pad_value = float(pad_values[dataset_name])
|
|
382
|
+
else:
|
|
383
|
+
pad_value = None
|
|
384
|
+
|
|
380
385
|
selection[dataset_name] = DatasetColumn(
|
|
381
386
|
dataset_name,
|
|
382
387
|
all_columns_dct[dataset_name],
|
|
@@ -387,7 +392,7 @@ def get_column_selection(hdf5_files: str | list[str], column_names: list[str]) -
|
|
|
387
392
|
numer_columns_idx_dct[dataset_name],
|
|
388
393
|
categ_columns_idx_dct[dataset_name],
|
|
389
394
|
shapes_dct[dataset_name],
|
|
390
|
-
|
|
395
|
+
pad_value,
|
|
391
396
|
labels,
|
|
392
397
|
)
|
|
393
398
|
|
|
@@ -8,7 +8,7 @@ import numpy as np
|
|
|
8
8
|
from torch.utils.data import DataLoader
|
|
9
9
|
|
|
10
10
|
from f9columnar.ml.dataloader_helpers import ColumnSelection, padding_mask
|
|
11
|
-
from f9columnar.ml.
|
|
11
|
+
from f9columnar.ml.hdf5_dataloader import WeightedDatasetBatch, get_ml_hdf5_dataloader
|
|
12
12
|
from f9columnar.ml.scalers import CategoricalFeatureScaler, FeatureScaler, NumericalFeatureScaler
|
|
13
13
|
from f9columnar.utils.loggers import get_batch_progress
|
|
14
14
|
|
|
@@ -8,7 +8,7 @@ import awkward as ak
|
|
|
8
8
|
import h5py
|
|
9
9
|
import numpy as np
|
|
10
10
|
|
|
11
|
-
from f9columnar.ml.
|
|
11
|
+
from f9columnar.ml.hdf5_writer import ArraysHdf5Writer
|
|
12
12
|
from f9columnar.processors import Processor
|
|
13
13
|
|
|
14
14
|
|
|
@@ -561,7 +561,10 @@ class Hdf5WriterProcessor(Processor):
|
|
|
561
561
|
|
|
562
562
|
writer.add_data(chunk_arrays_dct, current_dataset_name, idx=(start_idx, stop_idx), resize=resize)
|
|
563
563
|
|
|
564
|
-
def run(self, arrays:
|
|
564
|
+
def run(self, arrays: ak.Array) -> dict[str, ak.Array]:
|
|
565
|
+
if len(arrays) == 0:
|
|
566
|
+
return {"arrays": arrays}
|
|
567
|
+
|
|
565
568
|
worker_id = self.reports["worker_id"] # type: ignore[index]
|
|
566
569
|
self._setup_piles_lst(worker_id)
|
|
567
570
|
|
|
@@ -668,6 +668,9 @@ class Hdf5WriterPostprocessor(Postprocessor):
|
|
|
668
668
|
else:
|
|
669
669
|
raise AttributeError("Arrays attribute not found in the processor!")
|
|
670
670
|
|
|
671
|
+
if len(arrays) == 0:
|
|
672
|
+
return {"processors": processors}
|
|
673
|
+
|
|
671
674
|
if self.n_piles is not None:
|
|
672
675
|
n_add_iters = (len(arrays) + self.chunk_shape - 1) // self.chunk_shape
|
|
673
676
|
pile_idx_lst = [self._get_pile_idx() for _ in range(n_add_iters)]
|
|
@@ -4,6 +4,7 @@ import copy
|
|
|
4
4
|
import logging
|
|
5
5
|
import os
|
|
6
6
|
from collections.abc import Callable, Iterator
|
|
7
|
+
from concurrent.futures import ProcessPoolExecutor
|
|
7
8
|
from dataclasses import dataclass, field
|
|
8
9
|
from typing import Any
|
|
9
10
|
|
|
@@ -17,7 +18,6 @@ from torch.utils.data import DataLoader, IterableDataset
|
|
|
17
18
|
|
|
18
19
|
from f9columnar.processors import Processor, ProcessorsGraph
|
|
19
20
|
from f9columnar.utils.helpers import get_file_size
|
|
20
|
-
from f9columnar.utils.loggers import get_progress
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
@dataclass
|
|
@@ -66,11 +66,7 @@ class RootFiles:
|
|
|
66
66
|
total_file_size: float = 0.0
|
|
67
67
|
total_num_entries: int = 0
|
|
68
68
|
|
|
69
|
-
def
|
|
70
|
-
progress = get_progress()
|
|
71
|
-
progress.start()
|
|
72
|
-
bar = progress.add_task("Preparing ROOT files", total=len(self.file_names))
|
|
73
|
-
|
|
69
|
+
def load(self) -> RootFiles:
|
|
74
70
|
for i, file_name in enumerate(self.file_names):
|
|
75
71
|
if type(self.key) is list:
|
|
76
72
|
root_file = RootFile(file_name, self.key[i])
|
|
@@ -79,8 +75,6 @@ class RootFiles:
|
|
|
79
75
|
else:
|
|
80
76
|
raise ValueError(f"Key {self.key} is not a valid type.")
|
|
81
77
|
|
|
82
|
-
progress.update(bar, advance=1)
|
|
83
|
-
|
|
84
78
|
root_file = root_file.open()
|
|
85
79
|
|
|
86
80
|
self.files_dct[file_name] = root_file
|
|
@@ -98,7 +92,7 @@ class RootFiles:
|
|
|
98
92
|
self.total_file_size += root_file.file_size
|
|
99
93
|
self.total_num_entries += num_entries
|
|
100
94
|
|
|
101
|
-
|
|
95
|
+
return self
|
|
102
96
|
|
|
103
97
|
def __getitem__(self, file_name: str) -> RootFile:
|
|
104
98
|
return self.files_dct[file_name]
|
|
@@ -131,8 +125,49 @@ class UprootIteratorsDfMaker:
|
|
|
131
125
|
|
|
132
126
|
logging.info(info_str)
|
|
133
127
|
|
|
128
|
+
@staticmethod
|
|
129
|
+
def _run_get_root_files(files_lst: list[str], key: str | list[str], it) -> RootFiles:
|
|
130
|
+
return RootFiles(files_lst, key).load()
|
|
131
|
+
|
|
132
|
+
def _join_root_files(self, root_files: list[RootFiles]) -> RootFiles:
|
|
133
|
+
combined_files, combined_file_size_dct, combined_num_entries_dct = {}, {}, {}
|
|
134
|
+
|
|
135
|
+
total_file_size, total_num_entries = 0.0, 0
|
|
136
|
+
|
|
137
|
+
for root_file in root_files:
|
|
138
|
+
combined_files.update(root_file.files_dct)
|
|
139
|
+
combined_file_size_dct.update(root_file.file_size_dct)
|
|
140
|
+
combined_num_entries_dct.update(root_file.num_entries_dct)
|
|
141
|
+
|
|
142
|
+
total_file_size += root_file.total_file_size
|
|
143
|
+
total_num_entries += root_file.total_num_entries
|
|
144
|
+
|
|
145
|
+
return RootFiles(
|
|
146
|
+
list(combined_files.keys()),
|
|
147
|
+
key=self.key,
|
|
148
|
+
files_dct=combined_files,
|
|
149
|
+
file_size_dct=combined_file_size_dct,
|
|
150
|
+
num_entries_dct=combined_num_entries_dct,
|
|
151
|
+
total_file_size=total_file_size,
|
|
152
|
+
total_num_entries=total_num_entries,
|
|
153
|
+
)
|
|
154
|
+
|
|
134
155
|
def _split(self) -> list[dict[str, list[int]]]:
|
|
135
|
-
|
|
156
|
+
logging.info("Preparing ROOT files (this may take a while).")
|
|
157
|
+
|
|
158
|
+
jobs_idx_split = np.array_split(np.arange(len(self.files)), self.num_workers)
|
|
159
|
+
|
|
160
|
+
with ProcessPoolExecutor(max_workers=self.num_workers) as executor:
|
|
161
|
+
futures = []
|
|
162
|
+
for it, job_idx in enumerate(jobs_idx_split):
|
|
163
|
+
files_lst = [self.files[i] for i in job_idx]
|
|
164
|
+
futures.append(executor.submit(self._run_get_root_files, files_lst, self.key, it))
|
|
165
|
+
|
|
166
|
+
root_files_results = []
|
|
167
|
+
for future in futures:
|
|
168
|
+
root_files_results.append(future.result())
|
|
169
|
+
|
|
170
|
+
root_files = self._join_root_files(root_files_results)
|
|
136
171
|
|
|
137
172
|
self._log_info(root_files.total_file_size, root_files.total_num_entries)
|
|
138
173
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|