f9columnar 0.2.1__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.
Files changed (36) hide show
  1. {f9columnar-0.2.1 → f9columnar-0.2.2}/PKG-INFO +1 -1
  2. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/hdf5_dataloader.py +88 -33
  3. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/root_dataloader.py +10 -7
  4. {f9columnar-0.2.1 → f9columnar-0.2.2}/pyproject.toml +1 -1
  5. {f9columnar-0.2.1 → f9columnar-0.2.2}/README.md +0 -0
  6. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/__init__.py +0 -0
  7. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/analysis/__init__.py +0 -0
  8. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/analysis/triggers.py +0 -0
  9. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/arrays.py +0 -0
  10. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/data/PMGxsecDB_mc16.txt +0 -0
  11. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/data/PMGxsecDB_mc21.txt +0 -0
  12. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/data/campaigns.json +0 -0
  13. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/data/luminosity.json +0 -0
  14. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/data/periods.json +0 -0
  15. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/data/truth_classification.json +0 -0
  16. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/dataset_builder.py +0 -0
  17. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/hdf5_writer.py +0 -0
  18. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/histograms.py +0 -0
  19. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/processors.py +0 -0
  20. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/processors_collection.py +0 -0
  21. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/run.py +0 -0
  22. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/submit/__init__.py +0 -0
  23. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/submit/act_driver.py +0 -0
  24. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/submit/act_handler.py +0 -0
  25. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/submit/act_merger.py +0 -0
  26. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/submit/act_run.py +0 -0
  27. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/submit/act_run.sh +0 -0
  28. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/utils/__init__.py +0 -0
  29. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/utils/ak_helpers.py +0 -0
  30. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/utils/config_utils.py +0 -0
  31. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/utils/helpers.py +0 -0
  32. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/utils/loggers.py +0 -0
  33. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/utils/regex_helpers.py +0 -0
  34. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/utils/rucio_db.py +0 -0
  35. {f9columnar-0.2.1 → f9columnar-0.2.2}/f9columnar/utils/rucio_utils.py +0 -0
  36. {f9columnar-0.2.1 → 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.1
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
@@ -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 Hdf5IteratorMaker:
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 make(self) -> list[list[Hdf5Iterator]]:
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
- worker_hdf5_iterators: list[list] = [[] for _ in range(self.num_workers)]
190
- check_total = 0
191
+ return result
191
192
 
192
- for i, result_dct in enumerate(result):
193
- for hdf5_file, start_end in result_dct.items():
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
- iterator = self._make_iterator(hdf5_file, entry_start, entry_end)
198
- worker_hdf5_iterators[i].append(iterator)
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 worker_hdf5_iterators
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
- hdf5_iterators: list[Hdf5Iterator],
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.hdf5_iterators = hdf5_iterators
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
- current_iterator = self.hdf5_iterators[self.current_iterator_idx]
251
- arrays, reports = next(current_iterator)
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
- current_iterator.close()
293
+ self.iterator.close()
255
294
  self.current_iterator_idx += 1
256
295
 
257
- if self.current_iterator_idx == len(self.hdf5_iterators):
296
+ if self.current_iterator_idx == len(self.iterators_df):
258
297
  raise StopIteration
259
- else:
260
- current_iterator = self.hdf5_iterators[self.current_iterator_idx]
261
- arrays, reports = next(current_iterator)
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.worker_hdf5_iterators = self._get_iterators()
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 _get_iterators(self) -> list[list[Hdf5Iterator]]:
388
- return Hdf5IteratorMaker(
389
- self.name, self.metadata, self.num_workers, self.shape, self.chunk_size, self.shuffle, self.holdout_range
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
- hdf5_iterators = self.worker_hdf5_iterators[worker_id]
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
- hdf5_iterators,
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=lambda batch: batch,
512
+ collate_fn=default_collate_fn,
458
513
  **dataloader_kwargs,
459
514
  )
460
515
 
@@ -2,7 +2,6 @@ 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
@@ -12,6 +11,7 @@ import awkward as ak
12
11
  import pandas as pd
13
12
  import torch
14
13
  import uproot
14
+ from torch import multiprocessing
15
15
  from torch.utils.data import DataLoader, IterableDataset
16
16
 
17
17
  from f9columnar.processors import Processor, ProcessorsGraph
@@ -316,13 +316,13 @@ class RootIterableDataset(IterableDataset):
316
316
  def __init__(
317
317
  self,
318
318
  name: str,
319
- iterators_df: pd.DataFrame,
319
+ worker_iterators_df: pd.DataFrame,
320
320
  processors: list[Callable[[ak.Array, dict], tuple[ak.Array, dict]]] | ProcessorsGraph | None = None,
321
321
  filter_name: Callable[[str], bool] | None = None,
322
322
  root_files_desc_dct: dict[str, dict[str, Any]] | None = None,
323
323
  ) -> None:
324
324
  self.name = name
325
- self.iterators_df = iterators_df
325
+ self.worker_iterators_df = worker_iterators_df
326
326
  self.processors = processors
327
327
  self.filter_name = filter_name
328
328
  self.root_files_desc_dct = root_files_desc_dct
@@ -335,7 +335,7 @@ class RootIterableDataset(IterableDataset):
335
335
  else:
336
336
  worker_id = worker_info.id
337
337
 
338
- iterators_df = self.iterators_df[self.iterators_df["worker_id"] == worker_id].copy()
338
+ iterators_df = self.worker_iterators_df[self.worker_iterators_df["worker_id"] == worker_id].copy()
339
339
 
340
340
  return RootLoaderIterator(
341
341
  self.name,
@@ -358,6 +358,9 @@ def get_root_dataloader(
358
358
  dataloader_kwargs: dict[str, Any] | None = None,
359
359
  ) -> tuple[DataLoader, int]:
360
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
+
361
364
  if num_workers == -1:
362
365
  num_workers = multiprocessing.cpu_count()
363
366
 
@@ -366,14 +369,14 @@ def get_root_dataloader(
366
369
 
367
370
  logging.info("Making ROOT dataloader!")
368
371
 
369
- df_maker = UprootIteratorsDfMaker(name, files, key, step_size, num_workers)
370
- iteratorts_df = df_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()
371
374
 
372
375
  total_num_entries = df_maker.total_num_entries
373
376
 
374
377
  root_iterable_dataset = RootIterableDataset(
375
378
  name,
376
- iteratorts_df,
379
+ worker_iteratorts_df,
377
380
  processors=processors,
378
381
  filter_name=filter_name,
379
382
  root_files_desc_dct=root_files_desc_dct,
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "f9columnar"
3
- version = "0.2.1"
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"
File without changes
File without changes