f9columnar 0.2.0__tar.gz → 0.2.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.2.0 → f9columnar-0.2.2}/PKG-INFO +2 -1
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/hdf5_dataloader.py +88 -33
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/root_dataloader.py +116 -143
- {f9columnar-0.2.0 → f9columnar-0.2.2}/pyproject.toml +2 -1
- {f9columnar-0.2.0 → f9columnar-0.2.2}/README.md +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/__init__.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/analysis/__init__.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/analysis/triggers.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/arrays.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/data/PMGxsecDB_mc16.txt +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/data/PMGxsecDB_mc21.txt +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/data/campaigns.json +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/data/luminosity.json +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/data/periods.json +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/data/truth_classification.json +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/dataset_builder.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/hdf5_writer.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/histograms.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/processors.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/processors_collection.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/run.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/submit/__init__.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/submit/act_driver.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/submit/act_handler.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/submit/act_merger.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/submit/act_run.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/submit/act_run.sh +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/utils/__init__.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/utils/ak_helpers.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/utils/config_utils.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/utils/helpers.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/utils/loggers.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/utils/regex_helpers.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/utils/rucio_db.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/utils/rucio_utils.py +0 -0
- {f9columnar-0.2.0 → f9columnar-0.2.2}/f9columnar/utils/xsec_db.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: f9columnar
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Columnar analysis utils.
|
|
5
5
|
Home-page: https://gitlab.cern.ch/ijs-f9-ljubljana/f9columnar
|
|
6
6
|
License: MIT
|
|
@@ -24,6 +24,7 @@ Requires-Dist: numba (==0.60.0)
|
|
|
24
24
|
Requires-Dist: numpy (==2.0.2)
|
|
25
25
|
Requires-Dist: pandas (==2.2.2)
|
|
26
26
|
Requires-Dist: plothist (>=1.2.6,<2.0.0)
|
|
27
|
+
Requires-Dist: psutil (>=6.1.0,<7.0.0)
|
|
27
28
|
Requires-Dist: pydot (==3.0.1)
|
|
28
29
|
Requires-Dist: pygraphviz (==1.13)
|
|
29
30
|
Requires-Dist: requests (>=2.28.1,<3.0.0)
|
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
import copy
|
|
4
4
|
import json
|
|
5
5
|
import logging
|
|
6
|
-
import multiprocessing
|
|
7
6
|
import os
|
|
8
7
|
from collections.abc import Callable
|
|
9
8
|
from itertools import product
|
|
@@ -11,8 +10,10 @@ from typing import Any
|
|
|
11
10
|
|
|
12
11
|
import h5py
|
|
13
12
|
import numpy as np
|
|
13
|
+
import pandas as pd
|
|
14
14
|
import torch
|
|
15
15
|
from numpy.typing import ArrayLike
|
|
16
|
+
from torch import multiprocessing
|
|
16
17
|
from torch.utils.data import DataLoader, IterableDataset
|
|
17
18
|
|
|
18
19
|
from f9columnar.processors import Processor, ProcessorsGraph
|
|
@@ -95,7 +96,7 @@ class Hdf5Iterator:
|
|
|
95
96
|
return arrays, reports
|
|
96
97
|
|
|
97
98
|
|
|
98
|
-
class
|
|
99
|
+
class Hdf5IteratorDfMaker:
|
|
99
100
|
def __init__(
|
|
100
101
|
self,
|
|
101
102
|
name: str,
|
|
@@ -115,6 +116,7 @@ class Hdf5IteratorMaker:
|
|
|
115
116
|
self.holdout_range = holdout_range
|
|
116
117
|
|
|
117
118
|
self.total_num_entries = shape[0]
|
|
119
|
+
self.all_num_entries_dct: dict[str, int] = {}
|
|
118
120
|
|
|
119
121
|
def _log_info(self) -> None:
|
|
120
122
|
all_hdf5_files = list(self.hdf5_files_metadata.keys())
|
|
@@ -143,15 +145,15 @@ class Hdf5IteratorMaker:
|
|
|
143
145
|
holdout_range=self.holdout_range,
|
|
144
146
|
)
|
|
145
147
|
|
|
146
|
-
def
|
|
148
|
+
def _split(self) -> list[dict[str, list[int]]]:
|
|
147
149
|
self._log_info()
|
|
148
150
|
|
|
149
151
|
# how many entries each worker will process
|
|
150
152
|
splits = [self.total_num_entries // self.num_workers] * self.num_workers
|
|
151
153
|
splits[-1] += self.total_num_entries % self.num_workers
|
|
152
154
|
|
|
153
|
-
all_num_entries_dct = {file: metadata["shape"][0] for file, metadata in self.hdf5_files_metadata.items()}
|
|
154
|
-
num_entries_dct = copy.deepcopy(all_num_entries_dct)
|
|
155
|
+
self.all_num_entries_dct = {file: metadata["shape"][0] for file, metadata in self.hdf5_files_metadata.items()}
|
|
156
|
+
num_entries_dct = copy.deepcopy(self.all_num_entries_dct)
|
|
155
157
|
|
|
156
158
|
# keep track of the start and stop entries for each root file
|
|
157
159
|
hdf5_files_start_dct: dict[str, int] = {file: 0 for file in self.hdf5_files_metadata.keys()}
|
|
@@ -171,7 +173,7 @@ class Hdf5IteratorMaker:
|
|
|
171
173
|
total += num_entries
|
|
172
174
|
|
|
173
175
|
if total <= split:
|
|
174
|
-
result[i][hdf5_file] = [start_entry, all_num_entries_dct[hdf5_file]]
|
|
176
|
+
result[i][hdf5_file] = [start_entry, self.all_num_entries_dct[hdf5_file]]
|
|
175
177
|
done.append(hdf5_file)
|
|
176
178
|
|
|
177
179
|
if total == split:
|
|
@@ -186,39 +188,74 @@ class Hdf5IteratorMaker:
|
|
|
186
188
|
num_entries_dct[hdf5_file] -= delta
|
|
187
189
|
break
|
|
188
190
|
|
|
189
|
-
|
|
190
|
-
check_total = 0
|
|
191
|
+
return result
|
|
191
192
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
entry_start, entry_end = start_end
|
|
195
|
-
check_total += entry_end - entry_start
|
|
193
|
+
def make(self) -> pd.DataFrame:
|
|
194
|
+
split_result = self._split()
|
|
196
195
|
|
|
197
|
-
|
|
198
|
-
|
|
196
|
+
worker_df: dict[str, list] = {
|
|
197
|
+
"worker_id": [],
|
|
198
|
+
"file": [],
|
|
199
|
+
"start": [],
|
|
200
|
+
"stop": [],
|
|
201
|
+
"chunk_size": [],
|
|
202
|
+
"holdout_range": [],
|
|
203
|
+
"shuffle": [],
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
check_total = 0
|
|
207
|
+
for i, result_dct in enumerate(split_result):
|
|
208
|
+
for hdf5_file, start_stop in result_dct.items():
|
|
209
|
+
entry_start, entry_stop = start_stop
|
|
210
|
+
check_total += entry_stop - entry_start
|
|
211
|
+
|
|
212
|
+
worker_df["worker_id"].append(i)
|
|
213
|
+
worker_df["file"].append(hdf5_file)
|
|
214
|
+
worker_df["start"].append(entry_start)
|
|
215
|
+
worker_df["stop"].append(entry_stop)
|
|
216
|
+
worker_df["chunk_size"].append(self.chunk_size)
|
|
217
|
+
worker_df["holdout_range"].append(self.holdout_range)
|
|
218
|
+
worker_df["shuffle"].append(self.shuffle)
|
|
199
219
|
|
|
200
220
|
if check_total != self.total_num_entries:
|
|
201
221
|
raise ValueError("Total number of entries does not match.")
|
|
202
222
|
|
|
203
|
-
return
|
|
223
|
+
return pd.DataFrame(worker_df)
|
|
204
224
|
|
|
205
225
|
|
|
206
226
|
class Hdf5LoaderIterator:
|
|
207
227
|
def __init__(
|
|
208
228
|
self,
|
|
209
229
|
name: str,
|
|
210
|
-
|
|
230
|
+
iterators_df: pd.DataFrame,
|
|
211
231
|
worker_id: int,
|
|
212
232
|
processors: list[Callable[[ArrayLike, dict], tuple[ArrayLike, dict]]] | ProcessorsGraph | None,
|
|
213
233
|
hdf5_files_desc_dct: dict[str, dict[str, Any]] | None = None,
|
|
214
234
|
) -> None:
|
|
215
235
|
self.name = name
|
|
216
|
-
self.
|
|
236
|
+
self.iterators_df = iterators_df
|
|
217
237
|
self.worker_id = worker_id
|
|
218
238
|
self.processors = processors
|
|
219
239
|
self.hdf5_files_desc_dct = hdf5_files_desc_dct
|
|
220
240
|
|
|
221
|
-
self.current_iterator_idx = 0
|
|
241
|
+
self.current_df_idx, self.current_iterator_idx = 0, 0
|
|
242
|
+
|
|
243
|
+
def _make_hdf5_iterator(self, df: pd.Series) -> Hdf5Iterator:
|
|
244
|
+
iterator = Hdf5Iterator(
|
|
245
|
+
df["file"],
|
|
246
|
+
chunk_size=df["chunk_size"],
|
|
247
|
+
start_entry=df["start"],
|
|
248
|
+
stop_entry=df["stop"],
|
|
249
|
+
shuffle=df["shuffle"],
|
|
250
|
+
holdout_range=df["holdout_range"],
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
return iterator
|
|
254
|
+
|
|
255
|
+
def _iterate_df(self) -> None:
|
|
256
|
+
df = self.iterators_df.iloc[self.current_iterator_idx]
|
|
257
|
+
self.iterator = self._make_hdf5_iterator(df)
|
|
258
|
+
self.current_df_idx += 1
|
|
222
259
|
|
|
223
260
|
def _run_processors(self, arrays: ArrayLike, reports: dict) -> tuple[ArrayLike, dict] | dict[str, Processor]:
|
|
224
261
|
if self.processors is None:
|
|
@@ -247,18 +284,22 @@ class Hdf5LoaderIterator:
|
|
|
247
284
|
|
|
248
285
|
def __next__(self) -> tuple[ArrayLike, dict] | dict[str, Processor]:
|
|
249
286
|
try:
|
|
250
|
-
|
|
251
|
-
|
|
287
|
+
if self.current_df_idx == self.current_iterator_idx:
|
|
288
|
+
self._iterate_df()
|
|
289
|
+
|
|
290
|
+
arrays, reports = next(self.iterator)
|
|
252
291
|
|
|
253
292
|
except StopIteration:
|
|
254
|
-
|
|
293
|
+
self.iterator.close()
|
|
255
294
|
self.current_iterator_idx += 1
|
|
256
295
|
|
|
257
|
-
if self.current_iterator_idx == len(self.
|
|
296
|
+
if self.current_iterator_idx == len(self.iterators_df):
|
|
258
297
|
raise StopIteration
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
298
|
+
|
|
299
|
+
if self.current_df_idx == self.current_iterator_idx:
|
|
300
|
+
self._iterate_df()
|
|
301
|
+
|
|
302
|
+
arrays, reports = next(self.iterator)
|
|
262
303
|
|
|
263
304
|
reports = self._make_report(reports)
|
|
264
305
|
|
|
@@ -308,7 +349,7 @@ class Hdf5IterableDataset(IterableDataset):
|
|
|
308
349
|
|
|
309
350
|
self.shape = self._get_total_shape()
|
|
310
351
|
|
|
311
|
-
self.
|
|
352
|
+
self.worker_iterators_df = self._get_df_iterators()
|
|
312
353
|
|
|
313
354
|
def _setup(self) -> None:
|
|
314
355
|
for file, dataset_name in product(self.files, self.dataset_names):
|
|
@@ -384,9 +425,15 @@ class Hdf5IterableDataset(IterableDataset):
|
|
|
384
425
|
|
|
385
426
|
return sum(shapes_0), shapes_1[0]
|
|
386
427
|
|
|
387
|
-
def
|
|
388
|
-
return
|
|
389
|
-
self.name,
|
|
428
|
+
def _get_df_iterators(self) -> pd.DataFrame:
|
|
429
|
+
return Hdf5IteratorDfMaker(
|
|
430
|
+
self.name,
|
|
431
|
+
self.metadata,
|
|
432
|
+
self.num_workers,
|
|
433
|
+
self.shape,
|
|
434
|
+
self.chunk_size,
|
|
435
|
+
self.shuffle,
|
|
436
|
+
self.holdout_range,
|
|
390
437
|
).make()
|
|
391
438
|
|
|
392
439
|
def __iter__(self) -> Hdf5LoaderIterator:
|
|
@@ -397,17 +444,21 @@ class Hdf5IterableDataset(IterableDataset):
|
|
|
397
444
|
else:
|
|
398
445
|
worker_id = worker_info.id
|
|
399
446
|
|
|
400
|
-
|
|
447
|
+
iterators_df = self.worker_iterators_df[self.worker_iterators_df["worker_id"] == worker_id].copy()
|
|
401
448
|
|
|
402
449
|
return Hdf5LoaderIterator(
|
|
403
450
|
self.name,
|
|
404
|
-
|
|
451
|
+
iterators_df,
|
|
405
452
|
worker_id,
|
|
406
453
|
self.processors,
|
|
407
454
|
self.hdf5_files_desc_dct,
|
|
408
455
|
)
|
|
409
456
|
|
|
410
457
|
|
|
458
|
+
def default_collate_fn(batch: list[Any]) -> list[Any]:
|
|
459
|
+
return batch
|
|
460
|
+
|
|
461
|
+
|
|
411
462
|
def get_hdf5_dataloader(
|
|
412
463
|
name: str,
|
|
413
464
|
files: str | list[str],
|
|
@@ -421,6 +472,10 @@ def get_hdf5_dataloader(
|
|
|
421
472
|
processors: list[Callable[[ArrayLike, dict], tuple[ArrayLike, dict]]] | ProcessorsGraph | None = None,
|
|
422
473
|
dataloader_kwargs: dict[str, Any] | None = None,
|
|
423
474
|
) -> tuple[DataLoader, int]:
|
|
475
|
+
|
|
476
|
+
if multiprocessing.get_start_method() == "fork" and num_workers > 0:
|
|
477
|
+
logging.debug("Using 'fork' start method. Consider using 'spawn' or 'forkserver'.")
|
|
478
|
+
|
|
424
479
|
if num_workers == -1:
|
|
425
480
|
num_workers = multiprocessing.cpu_count()
|
|
426
481
|
|
|
@@ -441,7 +496,7 @@ def get_hdf5_dataloader(
|
|
|
441
496
|
name,
|
|
442
497
|
files,
|
|
443
498
|
dataset_names,
|
|
444
|
-
num_workers,
|
|
499
|
+
num_workers=num_workers if num_workers > 0 else 1,
|
|
445
500
|
chunk_size=chunk_size,
|
|
446
501
|
use_piles=use_piles,
|
|
447
502
|
shuffle=shuffle,
|
|
@@ -454,7 +509,7 @@ def get_hdf5_dataloader(
|
|
|
454
509
|
hdf5_dataset,
|
|
455
510
|
batch_size=None,
|
|
456
511
|
num_workers=num_workers,
|
|
457
|
-
collate_fn=
|
|
512
|
+
collate_fn=default_collate_fn,
|
|
458
513
|
**dataloader_kwargs,
|
|
459
514
|
)
|
|
460
515
|
|
|
@@ -2,19 +2,21 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import copy
|
|
4
4
|
import logging
|
|
5
|
-
import multiprocessing
|
|
6
5
|
import os
|
|
7
6
|
from collections.abc import Callable, Iterator
|
|
8
7
|
from dataclasses import dataclass, field
|
|
9
8
|
from typing import Any
|
|
10
9
|
|
|
11
10
|
import awkward as ak
|
|
11
|
+
import pandas as pd
|
|
12
12
|
import torch
|
|
13
13
|
import uproot
|
|
14
|
+
from torch import multiprocessing
|
|
14
15
|
from torch.utils.data import DataLoader, IterableDataset
|
|
15
16
|
|
|
16
17
|
from f9columnar.processors import Processor, ProcessorsGraph
|
|
17
18
|
from f9columnar.utils.helpers import get_file_size
|
|
19
|
+
from f9columnar.utils.loggers import get_progress
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
@dataclass
|
|
@@ -45,6 +47,10 @@ class RootFile:
|
|
|
45
47
|
self.num_entries = self.tree.num_entries
|
|
46
48
|
return self
|
|
47
49
|
|
|
50
|
+
def close(self) -> RootFile:
|
|
51
|
+
self.tree.close()
|
|
52
|
+
return self
|
|
53
|
+
|
|
48
54
|
|
|
49
55
|
@dataclass
|
|
50
56
|
class RootFiles:
|
|
@@ -60,6 +66,10 @@ class RootFiles:
|
|
|
60
66
|
total_num_entries: int = 0
|
|
61
67
|
|
|
62
68
|
def __post_init__(self) -> None:
|
|
69
|
+
progress = get_progress()
|
|
70
|
+
progress.start()
|
|
71
|
+
bar = progress.add_task("Preparing ROOT files", total=len(self.file_names))
|
|
72
|
+
|
|
63
73
|
for i, file_name in enumerate(self.file_names):
|
|
64
74
|
if type(self.key) is list:
|
|
65
75
|
root_file = RootFile(file_name, self.key[i])
|
|
@@ -68,89 +78,32 @@ class RootFiles:
|
|
|
68
78
|
else:
|
|
69
79
|
raise ValueError(f"Key {self.key} is not a valid type.")
|
|
70
80
|
|
|
81
|
+
progress.update(bar, advance=1)
|
|
82
|
+
|
|
71
83
|
root_file = root_file.open()
|
|
72
84
|
|
|
73
85
|
self.files_dct[file_name] = root_file
|
|
74
|
-
|
|
75
86
|
self.file_size_dct[file_name] = root_file.file_size
|
|
76
|
-
self.num_entries_dct[file_name] = root_file.num_entries
|
|
77
|
-
|
|
78
|
-
self.total_file_size += root_file.file_size
|
|
79
|
-
self.total_num_entries += root_file.num_entries
|
|
80
|
-
|
|
81
|
-
def __getitem__(self, file_name: str) -> RootFile:
|
|
82
|
-
return self.files_dct[file_name]
|
|
83
87
|
|
|
88
|
+
num_entries = root_file.num_entries
|
|
84
89
|
|
|
85
|
-
|
|
86
|
-
def __init__(
|
|
87
|
-
self,
|
|
88
|
-
root_file: RootFile,
|
|
89
|
-
step_size: int,
|
|
90
|
-
filter_name: Callable[[str], bool] | None = None,
|
|
91
|
-
entry_start: int | None = None,
|
|
92
|
-
entry_stop: int | None = None,
|
|
93
|
-
**kwargs: Any,
|
|
94
|
-
) -> None:
|
|
95
|
-
if type(step_size) is not int:
|
|
96
|
-
raise ValueError(f"Step size {step_size} is not an integer.")
|
|
90
|
+
root_file.close()
|
|
97
91
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
self.filter_name = filter_name
|
|
101
|
-
self.kwargs = kwargs
|
|
92
|
+
if num_entries == 0:
|
|
93
|
+
continue
|
|
102
94
|
|
|
103
|
-
|
|
95
|
+
self.num_entries_dct[file_name] = num_entries
|
|
104
96
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
self.entry_start = 0
|
|
108
|
-
else:
|
|
109
|
-
self.entry_start = entry_start
|
|
110
|
-
|
|
111
|
-
if entry_stop is None:
|
|
112
|
-
self.entry_stop = num_entries
|
|
113
|
-
else:
|
|
114
|
-
self.entry_stop = entry_stop
|
|
115
|
-
|
|
116
|
-
# handle cases where step size is larger than the number of entries
|
|
117
|
-
if self.entry_start is not None and self.entry_stop is not None:
|
|
118
|
-
delta_entry = self.entry_stop - self.entry_start
|
|
119
|
-
|
|
120
|
-
if self.step_size > delta_entry:
|
|
121
|
-
self.step_size = delta_entry
|
|
122
|
-
else:
|
|
123
|
-
if self.step_size > num_entries:
|
|
124
|
-
self.step_size = num_entries
|
|
125
|
-
|
|
126
|
-
self.tree: uproot.TTree = None
|
|
127
|
-
self.returned_iterator = False
|
|
128
|
-
|
|
129
|
-
def get_iterator(self) -> Iterator[tuple[ak.Array, Any]]:
|
|
130
|
-
if self.root_file.tree is None:
|
|
131
|
-
self.tree = uproot.open(self.root_file.file_name)
|
|
132
|
-
else:
|
|
133
|
-
self.tree = self.root_file.tree
|
|
134
|
-
|
|
135
|
-
uproot_iterator = self.tree.iterate(
|
|
136
|
-
library="ak",
|
|
137
|
-
report=True,
|
|
138
|
-
step_size=self.step_size,
|
|
139
|
-
filter_name=self.filter_name,
|
|
140
|
-
entry_start=self.entry_start,
|
|
141
|
-
entry_stop=self.entry_stop,
|
|
142
|
-
**self.kwargs,
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
self.returned_iterator = True
|
|
97
|
+
self.total_file_size += root_file.file_size
|
|
98
|
+
self.total_num_entries += num_entries
|
|
146
99
|
|
|
147
|
-
|
|
100
|
+
progress.stop()
|
|
148
101
|
|
|
149
|
-
def
|
|
150
|
-
self.
|
|
102
|
+
def __getitem__(self, file_name: str) -> RootFile:
|
|
103
|
+
return self.files_dct[file_name]
|
|
151
104
|
|
|
152
105
|
|
|
153
|
-
class
|
|
106
|
+
class UprootIteratorsDfMaker:
|
|
154
107
|
def __init__(
|
|
155
108
|
self,
|
|
156
109
|
name: str,
|
|
@@ -158,17 +111,14 @@ class UprootIteratorMaker:
|
|
|
158
111
|
key: str | list[str],
|
|
159
112
|
step_size: int,
|
|
160
113
|
num_workers: int,
|
|
161
|
-
filter_name: Callable[[str], bool] | None = None,
|
|
162
|
-
**kwargs: Any,
|
|
163
114
|
) -> None:
|
|
164
115
|
self.name = name
|
|
165
116
|
self.files, self.key = files, key
|
|
166
117
|
self.num_workers = num_workers
|
|
167
118
|
self.step_size = step_size
|
|
168
|
-
self.filter_name = filter_name
|
|
169
|
-
self.kwargs = kwargs
|
|
170
119
|
|
|
171
120
|
self.total_num_entries = 0
|
|
121
|
+
self.all_num_entries_dct: dict[str, int] = {}
|
|
172
122
|
|
|
173
123
|
def _log_info(self, total_files_size: float, total_num_entries: int) -> None:
|
|
174
124
|
info_str = "\n" + 15 * "=" + " info " + 15 * "="
|
|
@@ -180,17 +130,7 @@ class UprootIteratorMaker:
|
|
|
180
130
|
|
|
181
131
|
logging.info(info_str)
|
|
182
132
|
|
|
183
|
-
def
|
|
184
|
-
return UprootIterator(
|
|
185
|
-
root_file,
|
|
186
|
-
step_size=self.step_size,
|
|
187
|
-
filter_name=self.filter_name,
|
|
188
|
-
entry_start=entry_start,
|
|
189
|
-
entry_stop=entry_stop,
|
|
190
|
-
**self.kwargs,
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
def make(self) -> list[list[UprootIterator]]:
|
|
133
|
+
def _split(self) -> list[dict[str, list[int]]]:
|
|
194
134
|
root_files = RootFiles(self.files, self.key)
|
|
195
135
|
|
|
196
136
|
self._log_info(root_files.total_file_size, root_files.total_num_entries)
|
|
@@ -202,13 +142,13 @@ class UprootIteratorMaker:
|
|
|
202
142
|
splits = [total_num_entries // self.num_workers] * self.num_workers
|
|
203
143
|
splits[-1] += total_num_entries % self.num_workers
|
|
204
144
|
|
|
205
|
-
all_num_entries_dct = root_files.num_entries_dct
|
|
145
|
+
self.all_num_entries_dct = root_files.num_entries_dct
|
|
206
146
|
num_entries_dct = copy.deepcopy(root_files.num_entries_dct)
|
|
207
147
|
|
|
208
148
|
# keep track of the start and stop entries for each root file
|
|
209
149
|
root_files_start_dct: dict[str, int] = {root_file: 0 for root_file in self.files}
|
|
210
150
|
|
|
211
|
-
|
|
151
|
+
split_result: list[dict[str, list[int]]] = [{} for _ in range(len(splits))]
|
|
212
152
|
|
|
213
153
|
done = []
|
|
214
154
|
for i, split in enumerate(splits):
|
|
@@ -218,12 +158,12 @@ class UprootIteratorMaker:
|
|
|
218
158
|
if root_file in done:
|
|
219
159
|
continue
|
|
220
160
|
|
|
221
|
-
|
|
161
|
+
entry_start = root_files_start_dct[root_file]
|
|
222
162
|
|
|
223
163
|
total += num_entries
|
|
224
164
|
|
|
225
165
|
if total <= split:
|
|
226
|
-
|
|
166
|
+
split_result[i][root_file] = [entry_start, self.all_num_entries_dct[root_file]]
|
|
227
167
|
done.append(root_file)
|
|
228
168
|
|
|
229
169
|
if total == split:
|
|
@@ -233,45 +173,84 @@ class UprootIteratorMaker:
|
|
|
233
173
|
|
|
234
174
|
if total > split:
|
|
235
175
|
delta = num_entries - (total - split)
|
|
236
|
-
|
|
176
|
+
split_result[i][root_file] = [entry_start, entry_start + delta]
|
|
237
177
|
root_files_start_dct[root_file] += delta
|
|
238
178
|
num_entries_dct[root_file] -= delta
|
|
239
179
|
break
|
|
240
180
|
|
|
241
|
-
|
|
242
|
-
check_total = 0
|
|
181
|
+
return split_result
|
|
243
182
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
entry_start, entry_end = start_end
|
|
247
|
-
check_total += entry_end - entry_start
|
|
183
|
+
def make(self) -> pd.DataFrame:
|
|
184
|
+
split_result = self._split()
|
|
248
185
|
|
|
249
|
-
|
|
250
|
-
worker_uproot_iterators[i].append(iterator)
|
|
186
|
+
worker_df: dict[str, list] = {"worker_id": [], "file": [], "start": [], "stop": [], "step_size": []}
|
|
251
187
|
|
|
252
|
-
|
|
188
|
+
check_total = 0
|
|
189
|
+
for i, result_dct in enumerate(split_result):
|
|
190
|
+
for root_file, start_stop in result_dct.items():
|
|
191
|
+
entry_start, entry_stop = start_stop
|
|
192
|
+
check_total += entry_stop - entry_start
|
|
193
|
+
|
|
194
|
+
delta_entry = entry_stop - entry_start
|
|
195
|
+
num_entries = self.all_num_entries_dct[root_file]
|
|
196
|
+
|
|
197
|
+
if self.step_size > delta_entry:
|
|
198
|
+
step_size = delta_entry
|
|
199
|
+
elif self.step_size > num_entries:
|
|
200
|
+
step_size = num_entries
|
|
201
|
+
else:
|
|
202
|
+
step_size = self.step_size
|
|
203
|
+
|
|
204
|
+
worker_df["worker_id"].append(i)
|
|
205
|
+
worker_df["file"].append(f"{root_file}:{self.key}")
|
|
206
|
+
worker_df["start"].append(entry_start)
|
|
207
|
+
worker_df["stop"].append(entry_stop)
|
|
208
|
+
worker_df["step_size"].append(step_size)
|
|
209
|
+
|
|
210
|
+
if check_total != self.total_num_entries:
|
|
253
211
|
raise ValueError("Total number of entries does not match.")
|
|
254
212
|
|
|
255
|
-
return
|
|
213
|
+
return pd.DataFrame(worker_df)
|
|
256
214
|
|
|
257
215
|
|
|
258
216
|
class RootLoaderIterator:
|
|
259
217
|
def __init__(
|
|
260
218
|
self,
|
|
261
219
|
name: str,
|
|
262
|
-
|
|
263
|
-
worker_id: int,
|
|
220
|
+
iterators_df: pd.DataFrame,
|
|
264
221
|
processors: list[Callable[[ak.Array, dict], tuple[ak.Array, dict]]] | ProcessorsGraph | None = None,
|
|
222
|
+
filter_name: Callable[[str], bool] | None = None,
|
|
265
223
|
root_files_desc_dct: dict[str, dict[str, Any]] | None = None,
|
|
266
224
|
) -> None:
|
|
267
225
|
self.name = name
|
|
268
|
-
self.
|
|
269
|
-
self.worker_id = worker_id
|
|
226
|
+
self.iterators_df = iterators_df
|
|
270
227
|
self.processors = processors
|
|
228
|
+
self.filter_name = filter_name
|
|
271
229
|
self.root_files_desc_dct = root_files_desc_dct
|
|
272
230
|
|
|
273
|
-
self.
|
|
274
|
-
self.
|
|
231
|
+
self.iterator: Iterator
|
|
232
|
+
self.tree: uproot.TTree
|
|
233
|
+
|
|
234
|
+
self.current_df_idx, self.current_iterator_idx = 0, 0
|
|
235
|
+
|
|
236
|
+
def _make_uproot_iterator(self, df: pd.Series) -> tuple[Iterator, uproot.TTree]:
|
|
237
|
+
tree = uproot.open(df["file"])
|
|
238
|
+
|
|
239
|
+
iterator = tree.iterate(
|
|
240
|
+
library="ak",
|
|
241
|
+
report=True,
|
|
242
|
+
step_size=df["step_size"],
|
|
243
|
+
filter_name=self.filter_name,
|
|
244
|
+
entry_start=df["start"],
|
|
245
|
+
entry_stop=df["stop"],
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
return iterator, tree
|
|
249
|
+
|
|
250
|
+
def _iterate_df(self) -> None:
|
|
251
|
+
df = self.iterators_df.iloc[self.current_iterator_idx]
|
|
252
|
+
self.iterator, self.tree = self._make_uproot_iterator(df)
|
|
253
|
+
self.current_df_idx += 1
|
|
275
254
|
|
|
276
255
|
def _run_processors(self, arrays: ak.Array, reports: dict) -> tuple[ak.Array, dict] | dict[str, Processor]:
|
|
277
256
|
if self.processors is None:
|
|
@@ -281,8 +260,7 @@ class RootLoaderIterator:
|
|
|
281
260
|
arrays, reports = proc(arrays, reports)
|
|
282
261
|
return arrays, reports
|
|
283
262
|
elif type(self.processors) is ProcessorsGraph:
|
|
284
|
-
|
|
285
|
-
return processors
|
|
263
|
+
return self.processors.fit(arrays, reports)
|
|
286
264
|
else:
|
|
287
265
|
raise ValueError(f"Processors {self.processors} is not a valid type.")
|
|
288
266
|
|
|
@@ -293,7 +271,7 @@ class RootLoaderIterator:
|
|
|
293
271
|
|
|
294
272
|
reports = {
|
|
295
273
|
"name": self.name,
|
|
296
|
-
"worker_id": self.worker_id,
|
|
274
|
+
"worker_id": self.iterators_df.iloc[self.current_iterator_idx]["worker_id"],
|
|
297
275
|
"file_path": file_path,
|
|
298
276
|
"file": file_name,
|
|
299
277
|
"start": start,
|
|
@@ -310,23 +288,22 @@ class RootLoaderIterator:
|
|
|
310
288
|
|
|
311
289
|
def __next__(self) -> tuple[ak.Array, dict] | dict[str, Processor]:
|
|
312
290
|
try:
|
|
313
|
-
|
|
291
|
+
if self.current_df_idx == self.current_iterator_idx:
|
|
292
|
+
self._iterate_df()
|
|
314
293
|
|
|
315
|
-
|
|
316
|
-
self.current_iterator = uproot_iterator.get_iterator()
|
|
317
|
-
|
|
318
|
-
arrays, reports = next(self.current_iterator)
|
|
294
|
+
arrays, reports = next(self.iterator)
|
|
319
295
|
|
|
320
296
|
except StopIteration:
|
|
321
|
-
|
|
297
|
+
self.tree.close()
|
|
322
298
|
self.current_iterator_idx += 1
|
|
323
299
|
|
|
324
|
-
if self.current_iterator_idx == len(self.
|
|
300
|
+
if self.current_iterator_idx == len(self.iterators_df):
|
|
325
301
|
raise StopIteration
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
self.
|
|
329
|
-
|
|
302
|
+
|
|
303
|
+
if self.current_df_idx == self.current_iterator_idx:
|
|
304
|
+
self._iterate_df()
|
|
305
|
+
|
|
306
|
+
arrays, reports = next(self.iterator)
|
|
330
307
|
|
|
331
308
|
reports = self._make_report(reports)
|
|
332
309
|
|
|
@@ -339,13 +316,15 @@ class RootIterableDataset(IterableDataset):
|
|
|
339
316
|
def __init__(
|
|
340
317
|
self,
|
|
341
318
|
name: str,
|
|
342
|
-
|
|
319
|
+
worker_iterators_df: pd.DataFrame,
|
|
343
320
|
processors: list[Callable[[ak.Array, dict], tuple[ak.Array, dict]]] | ProcessorsGraph | None = None,
|
|
321
|
+
filter_name: Callable[[str], bool] | None = None,
|
|
344
322
|
root_files_desc_dct: dict[str, dict[str, Any]] | None = None,
|
|
345
323
|
) -> None:
|
|
346
324
|
self.name = name
|
|
347
|
-
self.
|
|
325
|
+
self.worker_iterators_df = worker_iterators_df
|
|
348
326
|
self.processors = processors
|
|
327
|
+
self.filter_name = filter_name
|
|
349
328
|
self.root_files_desc_dct = root_files_desc_dct
|
|
350
329
|
|
|
351
330
|
def __iter__(self) -> RootLoaderIterator:
|
|
@@ -356,13 +335,13 @@ class RootIterableDataset(IterableDataset):
|
|
|
356
335
|
else:
|
|
357
336
|
worker_id = worker_info.id
|
|
358
337
|
|
|
359
|
-
|
|
338
|
+
iterators_df = self.worker_iterators_df[self.worker_iterators_df["worker_id"] == worker_id].copy()
|
|
360
339
|
|
|
361
340
|
return RootLoaderIterator(
|
|
362
341
|
self.name,
|
|
363
|
-
|
|
364
|
-
worker_id,
|
|
342
|
+
iterators_df,
|
|
365
343
|
processors=self.processors,
|
|
344
|
+
filter_name=self.filter_name,
|
|
366
345
|
root_files_desc_dct=self.root_files_desc_dct,
|
|
367
346
|
)
|
|
368
347
|
|
|
@@ -376,46 +355,40 @@ def get_root_dataloader(
|
|
|
376
355
|
processors: list[Callable[[ak.Array, dict], tuple[ak.Array, dict]]] | ProcessorsGraph | None = None,
|
|
377
356
|
filter_name: Callable[[str], bool] | None = None,
|
|
378
357
|
root_files_desc_dct: dict[str, dict[str, Any]] | None = None,
|
|
379
|
-
uproot_kwargs: dict[str, Any] | None = None,
|
|
380
358
|
dataloader_kwargs: dict[str, Any] | None = None,
|
|
381
359
|
) -> tuple[DataLoader, int]:
|
|
382
360
|
|
|
361
|
+
if multiprocessing.get_start_method() == "fork" and num_workers > 0:
|
|
362
|
+
logging.debug("Using 'fork' start method. Consider using 'spawn' or 'forkserver'.")
|
|
363
|
+
|
|
383
364
|
if num_workers == -1:
|
|
384
365
|
num_workers = multiprocessing.cpu_count()
|
|
385
366
|
|
|
386
|
-
if uproot_kwargs is None:
|
|
387
|
-
uproot_kwargs = {}
|
|
388
|
-
|
|
389
367
|
if dataloader_kwargs is None:
|
|
390
368
|
dataloader_kwargs = {}
|
|
391
369
|
|
|
392
370
|
logging.info("Making ROOT dataloader!")
|
|
393
371
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
files,
|
|
397
|
-
key,
|
|
398
|
-
step_size,
|
|
399
|
-
num_workers,
|
|
400
|
-
filter_name=filter_name,
|
|
401
|
-
**uproot_kwargs,
|
|
402
|
-
)
|
|
403
|
-
worker_uproot_iterators = uproot_iterator_maker.make()
|
|
372
|
+
df_maker = UprootIteratorsDfMaker(name, files, key, step_size, num_workers if num_workers > 0 else 1)
|
|
373
|
+
worker_iteratorts_df = df_maker.make()
|
|
404
374
|
|
|
405
|
-
total_num_entries =
|
|
375
|
+
total_num_entries = df_maker.total_num_entries
|
|
406
376
|
|
|
407
377
|
root_iterable_dataset = RootIterableDataset(
|
|
408
378
|
name,
|
|
409
|
-
|
|
379
|
+
worker_iteratorts_df,
|
|
410
380
|
processors=processors,
|
|
381
|
+
filter_name=filter_name,
|
|
411
382
|
root_files_desc_dct=root_files_desc_dct,
|
|
412
383
|
)
|
|
413
384
|
|
|
385
|
+
prefetch_factor = dataloader_kwargs.get("prefetch_factor", None)
|
|
386
|
+
|
|
414
387
|
root_dataloader = DataLoader(
|
|
415
388
|
root_iterable_dataset,
|
|
416
389
|
batch_size=None,
|
|
417
390
|
num_workers=num_workers,
|
|
418
|
-
prefetch_factor=
|
|
391
|
+
prefetch_factor=prefetch_factor,
|
|
419
392
|
**dataloader_kwargs,
|
|
420
393
|
)
|
|
421
394
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "f9columnar"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.2"
|
|
4
4
|
description = "Columnar analysis utils."
|
|
5
5
|
authors = ["Jan Gavranovic <jan.gavranovic@cern.ch>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -28,6 +28,7 @@ requests = "^2.28.1"
|
|
|
28
28
|
tqdm = "^4.65.0"
|
|
29
29
|
networkx = "3.3"
|
|
30
30
|
rich = "^13.7.0"
|
|
31
|
+
psutil = "^6.1.0"
|
|
31
32
|
mplhep = "^0.3.50"
|
|
32
33
|
uproot = "5.3.10"
|
|
33
34
|
awkward = "2.6.7"
|
|
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
|