reboost 0.6.2__tar.gz → 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. {reboost-0.6.2 → reboost-0.7.0}/PKG-INFO +4 -4
  2. {reboost-0.6.2 → reboost-0.7.0}/pyproject.toml +3 -3
  3. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/_version.py +16 -3
  4. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/build_hit.py +102 -58
  5. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/cli.py +1 -0
  6. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/core.py +18 -7
  7. reboost-0.7.0/src/reboost/daq/__init__.py +5 -0
  8. reboost-0.7.0/src/reboost/daq/core.py +262 -0
  9. reboost-0.7.0/src/reboost/daq/utils.py +28 -0
  10. reboost-0.7.0/src/reboost/hpge/psd.py +845 -0
  11. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/hpge/surface.py +34 -1
  12. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/hpge/utils.py +2 -1
  13. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/iterator.py +4 -1
  14. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/math/stats.py +2 -2
  15. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/optmap/cli.py +1 -1
  16. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/optmap/convolve.py +270 -24
  17. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/optmap/create.py +2 -1
  18. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/optmap/optmap.py +2 -2
  19. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/shape/cluster.py +4 -4
  20. reboost-0.7.0/src/reboost/spms/__init__.py +5 -0
  21. reboost-0.7.0/src/reboost/spms/pe.py +99 -0
  22. reboost-0.7.0/src/reboost/units.py +107 -0
  23. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/utils.py +64 -2
  24. {reboost-0.6.2 → reboost-0.7.0}/src/reboost.egg-info/PKG-INFO +4 -4
  25. {reboost-0.6.2 → reboost-0.7.0}/src/reboost.egg-info/SOURCES.txt +6 -0
  26. {reboost-0.6.2 → reboost-0.7.0}/src/reboost.egg-info/requires.txt +2 -2
  27. {reboost-0.6.2 → reboost-0.7.0}/tests/conftest.py +1 -1
  28. {reboost-0.6.2 → reboost-0.7.0}/tests/hit/configs/basic.yaml +0 -1
  29. {reboost-0.6.2 → reboost-0.7.0}/tests/hit/configs/hit_config.yaml +0 -1
  30. reboost-0.7.0/tests/hit/configs/spms.yaml +30 -0
  31. {reboost-0.6.2 → reboost-0.7.0}/tests/hit/test_build_hit.py +66 -6
  32. reboost-0.7.0/tests/hpge/test_current.py +185 -0
  33. {reboost-0.6.2 → reboost-0.7.0}/tests/hpge/test_surface.py +8 -1
  34. {reboost-0.6.2 → reboost-0.7.0}/tests/test_optmap.py +10 -8
  35. {reboost-0.6.2 → reboost-0.7.0}/tests/test_units.py +29 -0
  36. {reboost-0.6.2 → reboost-0.7.0}/tests/test_utils.py +7 -0
  37. reboost-0.6.2/src/reboost/hpge/psd.py +0 -495
  38. reboost-0.6.2/src/reboost/units.py +0 -75
  39. reboost-0.6.2/tests/hpge/test_current.py +0 -21
  40. {reboost-0.6.2 → reboost-0.7.0}/LICENSE +0 -0
  41. {reboost-0.6.2 → reboost-0.7.0}/README.md +0 -0
  42. {reboost-0.6.2 → reboost-0.7.0}/setup.cfg +0 -0
  43. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/__init__.py +0 -0
  44. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/build_evt.py +0 -0
  45. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/build_glm.py +0 -0
  46. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/hpge/__init__.py +0 -0
  47. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/log_utils.py +0 -0
  48. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/math/__init__.py +0 -0
  49. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/math/functions.py +0 -0
  50. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/optmap/__init__.py +0 -0
  51. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/optmap/evt.py +0 -0
  52. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/optmap/mapview.py +0 -0
  53. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/optmap/numba_pdg.py +0 -0
  54. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/profile.py +0 -0
  55. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/shape/__init__.py +0 -0
  56. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/shape/group.py +0 -0
  57. {reboost-0.6.2 → reboost-0.7.0}/src/reboost/shape/reduction.py +0 -0
  58. {reboost-0.6.2 → reboost-0.7.0}/src/reboost.egg-info/dependency_links.txt +0 -0
  59. {reboost-0.6.2 → reboost-0.7.0}/src/reboost.egg-info/entry_points.txt +0 -0
  60. {reboost-0.6.2 → reboost-0.7.0}/src/reboost.egg-info/not-zip-safe +0 -0
  61. {reboost-0.6.2 → reboost-0.7.0}/src/reboost.egg-info/top_level.txt +0 -0
  62. {reboost-0.6.2 → reboost-0.7.0}/tests/evt/test_evt.py +0 -0
  63. {reboost-0.6.2 → reboost-0.7.0}/tests/glm/test_build_glm.py +0 -0
  64. {reboost-0.6.2 → reboost-0.7.0}/tests/hit/configs/args.yaml +0 -0
  65. {reboost-0.6.2 → reboost-0.7.0}/tests/hit/configs/foward_only.yaml +0 -0
  66. {reboost-0.6.2 → reboost-0.7.0}/tests/hit/configs/geom.gdml +0 -0
  67. {reboost-0.6.2 → reboost-0.7.0}/tests/hit/configs/pars.yaml +0 -0
  68. {reboost-0.6.2 → reboost-0.7.0}/tests/hit/configs/reshape.yaml +0 -0
  69. {reboost-0.6.2 → reboost-0.7.0}/tests/hpge/simulation/gammas.mac +0 -0
  70. {reboost-0.6.2 → reboost-0.7.0}/tests/hpge/simulation/geometry.gdml +0 -0
  71. {reboost-0.6.2 → reboost-0.7.0}/tests/hpge/simulation/make_dt_map.jl +0 -0
  72. {reboost-0.6.2 → reboost-0.7.0}/tests/hpge/simulation/make_geom.py +0 -0
  73. {reboost-0.6.2 → reboost-0.7.0}/tests/hpge/test_dt_heuristic.py +0 -0
  74. {reboost-0.6.2 → reboost-0.7.0}/tests/hpge/test_files/drift_time_maps.lh5 +0 -0
  75. {reboost-0.6.2 → reboost-0.7.0}/tests/hpge/test_files/internal_electron.lh5 +0 -0
  76. {reboost-0.6.2 → reboost-0.7.0}/tests/hpge/test_hpge_map.py +0 -0
  77. {reboost-0.6.2 → reboost-0.7.0}/tests/hpge/test_r90.py +0 -0
  78. {reboost-0.6.2 → reboost-0.7.0}/tests/test_cli.py +0 -0
  79. {reboost-0.6.2 → reboost-0.7.0}/tests/test_core.py +0 -0
  80. {reboost-0.6.2 → reboost-0.7.0}/tests/test_math.py +0 -0
  81. {reboost-0.6.2 → reboost-0.7.0}/tests/test_optmap_dets.gdml +0 -0
  82. {reboost-0.6.2 → reboost-0.7.0}/tests/test_profile.py +0 -0
  83. {reboost-0.6.2 → reboost-0.7.0}/tests/test_shape.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reboost
3
- Version: 0.6.2
3
+ Version: 0.7.0
4
4
  Summary: New LEGEND Monte-Carlo simulation post-processing
5
5
  Author-email: Manuel Huber <info@manuelhu.de>, Toby Dixon <toby.dixon.23@ucl.ac.uk>, Luigi Pertoldi <gipert@pm.me>
6
6
  Maintainer: The LEGEND Collaboration
@@ -693,7 +693,7 @@ Classifier: Programming Language :: Python
693
693
  Classifier: Programming Language :: Python :: 3
694
694
  Classifier: Programming Language :: Python :: 3 :: Only
695
695
  Classifier: Topic :: Scientific/Engineering
696
- Requires-Python: >=3.9
696
+ Requires-Python: >=3.10
697
697
  Description-Content-Type: text/markdown
698
698
  License-File: LICENSE
699
699
  Requires-Dist: hdf5plugin
@@ -701,8 +701,8 @@ Requires-Dist: colorlog
701
701
  Requires-Dist: numpy
702
702
  Requires-Dist: scipy
703
703
  Requires-Dist: numba
704
- Requires-Dist: legend-pydataobj>=1.14
705
- Requires-Dist: legend-pygeom-optics>=0.9.2
704
+ Requires-Dist: legend-pydataobj>=1.15.1
705
+ Requires-Dist: legend-pygeom-optics>=0.12.0
706
706
  Requires-Dist: legend-pygeom-tools>=0.0.11
707
707
  Requires-Dist: hist
708
708
  Requires-Dist: dbetto
@@ -30,15 +30,15 @@ classifiers = [
30
30
  "Programming Language :: Python :: 3 :: Only",
31
31
  "Topic :: Scientific/Engineering",
32
32
  ]
33
- requires-python = ">=3.9"
33
+ requires-python = ">=3.10"
34
34
  dependencies = [
35
35
  "hdf5plugin",
36
36
  "colorlog",
37
37
  "numpy",
38
38
  "scipy",
39
39
  "numba",
40
- "legend-pydataobj >=1.14",
41
- "legend-pygeom-optics >=0.9.2",
40
+ "legend-pydataobj >=1.15.1",
41
+ "legend-pygeom-optics >=0.12.0",
42
42
  "legend-pygeom-tools >=0.0.11",
43
43
  "hist",
44
44
  "dbetto",
@@ -1,7 +1,14 @@
1
1
  # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
3
 
4
- __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
5
12
 
6
13
  TYPE_CHECKING = False
7
14
  if TYPE_CHECKING:
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
9
16
  from typing import Union
10
17
 
11
18
  VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
12
20
  else:
13
21
  VERSION_TUPLE = object
22
+ COMMIT_ID = object
14
23
 
15
24
  version: str
16
25
  __version__: str
17
26
  __version_tuple__: VERSION_TUPLE
18
27
  version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
19
30
 
20
- __version__ = version = '0.6.2'
21
- __version_tuple__ = version_tuple = (0, 6, 2)
31
+ __version__ = version = '0.7.0'
32
+ __version_tuple__ = version_tuple = (0, 7, 0)
33
+
34
+ __commit_id__ = commit_id = 'gbfb61789b'
@@ -7,11 +7,16 @@ A :func:`build_hit` to parse the following configuration file:
7
7
  # dictionary of objects useful for later computation. they are constructed with
8
8
  # auxiliary data (e.g. metadata). They can be accessed later as OBJECTS (all caps)
9
9
  objects:
10
- lmeta: LegendMetadata(ARGS.legendmetadata)
10
+ lmeta: legendmeta.LegendMetadata(ARGS.legendmetadata)
11
11
  geometry: pyg4ometry.load(ARGS.gdml)
12
12
  user_pars: dbetto.TextDB(ARGS.par)
13
13
  dataprod_pars: dbetto.TextDB(ARGS.dataprod_cycle)
14
14
 
15
+ _spms: OBJECTS.lmeta.channelmap(on=ARGS.timestamp)
16
+ .group("system").spms
17
+ .map("name")
18
+ spms: "{name: spm.daq.rawid for name, spm in OBJECTS._spms.items()}"
19
+
15
20
  # processing chain is defined to act on a group of detectors
16
21
  processing_groups:
17
22
 
@@ -107,9 +112,10 @@ A :func:`build_hit` to parse the following configuration file:
107
112
  outputs:
108
113
  - evtid
109
114
  - tot_edep_wlsr
115
+ - num_scint_ph_lar
110
116
 
111
117
  operations:
112
- tot_edep_wlsr: ak.sum(HITS[(HITS.__detuid == 0) & (HITS.__zloc < 3000)].__edep, axis=-1)
118
+ tot_edep_wlsr: ak.sum(HITS.edep[np.abs(HITS.zloc) < 3000], axis=-1)
113
119
 
114
120
  - name: spms
115
121
 
@@ -117,11 +123,14 @@ A :func:`build_hit` to parse the following configuration file:
117
123
  # same name as the current detector. This can be overridden for special processors
118
124
 
119
125
  detector_mapping:
120
- - output: OBJECTS.lmeta.channglmap(on=ARGS.timestamp)
121
- .group("system").spms
122
- .group("analysis.status").on
123
- .map("name").keys()
124
- - input: lar
126
+ - output: OBJECTS.spms.keys()
127
+ input: lar
128
+
129
+ hit_table_layout: reboost.shape.group_by_time(STEPS, window=10)
130
+
131
+ pre_operations:
132
+ num_scint_ph_lar: reboost.spms.emitted_scintillation_photons(HITS.edep, HITS.particle, "lar")
133
+ # num_scint_ph_pen: ...
125
134
 
126
135
  outputs:
127
136
  - t0
@@ -130,22 +139,23 @@ A :func:`build_hit` to parse the following configuration file:
130
139
 
131
140
  detector_objects:
132
141
  meta: pygeomtools.get_sensvol_metadata(OBJECTS.geometry, DETECTOR)
133
- optmap_lar: lgdo.lh5.read(DETECTOR, "optmaps/pen", ARGS.optmap_path)
134
- optmap_pen: lgdo.lh5.read(DETECTOR, "optmaps/lar", ARGS.optmap_path)
135
-
136
- hit_table_layout: reboost.shape.group_by_time(STEPS, window=10)
142
+ spm_uid: OBJECTS.spms[DETECTOR]
143
+ optmap_lar: reboost.spms.load_optmap(ARGS.optmap_path_pen, DETECTOR_OBJECTS.spm_uid)
144
+ optmap_pen: reboost.spms.load_optmap(ARGS.optmap_path_lar, DETECTOR_OBJECTS.spm_uid)
137
145
 
138
146
  operations:
139
147
  pe_times_lar: reboost.spms.detected_photoelectrons(
140
- STEPS,
148
+ HITS.num_scint_ph_lar, HITS.particle, HITS.time, HITS.xloc, HITS.yloc, HITS.zloc,
141
149
  DETECTOR_OBJECTS.optmap_lar,
142
- 0
150
+ "lar",
151
+ DETECTOR_OBJECTS.spm_uid
143
152
  )
144
153
 
145
154
  pe_times_pen: reboost.spms.detected_photoelectrons(
146
- STEPS,
155
+ HITS.num_scint_ph_pen, HITS.particle, HITS.time, HITS.xloc, HITS.yloc, HITS.zloc,
147
156
  DETECTOR_OBJECTS.optmap_pen,
148
- 1
157
+ "pen",
158
+ DETECTOR_OBJECTS.spm_uid
149
159
  )
150
160
 
151
161
  pe_times: ak.concatenate([HITS.pe_times_lar, HITS.pe_times_pen], axis=-1)
@@ -189,6 +199,7 @@ def build_hit(
189
199
  out_field: str = "hit",
190
200
  buffer: int = int(5e6),
191
201
  overwrite: bool = False,
202
+ allow_missing_inputs=True,
192
203
  ) -> None | ak.Array:
193
204
  """Build the hit tier from the remage step files.
194
205
 
@@ -215,6 +226,8 @@ def build_hit(
215
226
  buffer size for use in the `LH5Iterator`.
216
227
  overwrite
217
228
  flag to overwrite the existing output.
229
+ allow_missing_inputs
230
+ Flag to allow an input table to be missing, generally when there were no events.
218
231
  """
219
232
  # extract the config file
220
233
  if isinstance(config, str):
@@ -238,7 +251,7 @@ def build_hit(
238
251
  output_tables_names = set()
239
252
 
240
253
  # iterate over files
241
- for file_idx, (stp_file, glm_file) in enumerate(zip(files.stp, files.glm)):
254
+ for file_idx, (stp_file, glm_file) in enumerate(zip(files.stp, files.glm, strict=True)):
242
255
  msg = (
243
256
  f"starting processing of {stp_file} to {files.hit[file_idx]} "
244
257
  if files.hit[file_idx] is not None
@@ -257,7 +270,7 @@ def build_hit(
257
270
 
258
271
  # extract the output detectors and the mapping to input detectors
259
272
  detectors_mapping = core.get_detector_mapping(
260
- proc_group.get("detector_mapping"), global_objects
273
+ proc_group.get("detector_mapping"), global_objects, args
261
274
  )
262
275
 
263
276
  # loop over detectors
@@ -276,20 +289,30 @@ def build_hit(
276
289
 
277
290
  lh5_group = proc_group.get("lh5_group", "stp")
278
291
  if lh5_group is None:
279
- lh5_group = "/"
292
+ lh5_group = ""
293
+ table = in_detector
294
+ else:
295
+ table = f"{lh5_group}/{in_detector}"
280
296
 
281
297
  # begin iterating over the glm
282
- iterator = GLMIterator(
283
- glm_file,
284
- stp_file,
285
- lh5_group=in_detector,
286
- start_row=start_evtid,
287
- stp_field=lh5_group,
288
- n_rows=n_evtid,
289
- buffer=buffer,
290
- time_dict=time_dict[proc_name],
291
- reshaped_files="hit_table_layout" not in proc_group,
292
- )
298
+ # check if the in_detector is in the file
299
+ if table in lh5.ls(stp_file, lh5_group + "/"):
300
+ iterator = GLMIterator(
301
+ glm_file,
302
+ stp_file,
303
+ lh5_group=in_detector,
304
+ start_row=start_evtid,
305
+ stp_field=lh5_group,
306
+ n_rows=n_evtid,
307
+ buffer=buffer,
308
+ time_dict=time_dict[proc_name],
309
+ reshaped_files="hit_table_layout" not in proc_group,
310
+ )
311
+ elif allow_missing_inputs:
312
+ continue
313
+ else:
314
+ msg = f"Requested input detector {in_detector} is not present in the group {lh5_group} and missing inputs were not allowed"
315
+ raise ValueError(msg)
293
316
 
294
317
  for stps, chunk_idx, _ in iterator:
295
318
  # converting to awkward
@@ -305,6 +328,21 @@ def build_hit(
305
328
  if time_dict is not None:
306
329
  time_dict[proc_name].update_field("conv", start_time)
307
330
 
331
+ if "hit_table_layout" in proc_group:
332
+ hit_table_layouted = core.evaluate_hit_table_layout(
333
+ copy.deepcopy(ak_obj),
334
+ expression=proc_group["hit_table_layout"],
335
+ time_dict=time_dict[proc_name],
336
+ )
337
+ else:
338
+ hit_table_layouted = copy.deepcopy(stps)
339
+
340
+ local_dict = {"OBJECTS": global_objects}
341
+ for field, info in proc_group.get("pre_operations", {}).items():
342
+ _evaluate_operation(
343
+ hit_table_layouted, field, info, local_dict, time_dict[proc_name]
344
+ )
345
+
308
346
  # produce the hit table
309
347
  for out_det_idx, out_detector in enumerate(out_detectors):
310
348
  # loop over the rows
@@ -314,14 +352,12 @@ def build_hit(
314
352
  # get the attributes
315
353
  attrs = utils.copy_units(stps)
316
354
 
317
- if "hit_table_layout" in proc_group:
318
- hit_table = core.evaluate_hit_table_layout(
319
- copy.deepcopy(ak_obj),
320
- expression=proc_group["hit_table_layout"],
321
- time_dict=time_dict[proc_name],
322
- )
323
- else:
324
- hit_table = copy.deepcopy(stps)
355
+ # if we have more than one output detector, make an independent copy.
356
+ hit_table = (
357
+ copy.deepcopy(hit_table_layouted)
358
+ if len(out_detectors) > 1
359
+ else hit_table_layouted
360
+ )
325
361
 
326
362
  local_dict = {
327
363
  "DETECTOR_OBJECTS": det_objects[out_detector],
@@ -330,28 +366,10 @@ def build_hit(
330
366
  }
331
367
  # add fields
332
368
  for field, info in proc_group.get("operations", {}).items():
333
- if isinstance(info, str):
334
- expression = info
335
- units = None
336
- else:
337
- expression = info["expression"]
338
- units = info.get("units", None)
339
-
340
- # evaluate the expression
341
- col = core.evaluate_output_column(
342
- hit_table,
343
- table_name="HITS",
344
- expression=expression,
345
- local_dict=local_dict,
346
- time_dict=time_dict[proc_name],
347
- name=field,
369
+ _evaluate_operation(
370
+ hit_table, field, info, local_dict, time_dict[proc_name]
348
371
  )
349
372
 
350
- if units is not None:
351
- col.attrs["units"] = units
352
-
353
- core.add_field_with_nesting(hit_table, field, col)
354
-
355
373
  # remove unwanted fields
356
374
  if "outputs" in proc_group:
357
375
  hit_table = core.remove_columns(
@@ -414,9 +432,35 @@ def build_hit(
414
432
  raise RuntimeError(msg) from e
415
433
 
416
434
  # return output table or nothing
417
- log.debug(time_dict)
435
+ log.info(time_dict)
418
436
 
419
437
  if output_tables == {}:
420
438
  output_tables = None
421
439
 
422
440
  return output_tables, time_dict
441
+
442
+
443
+ def _evaluate_operation(
444
+ hit_table, field: str, info: str | dict, local_dict: dict, time_dict: ProfileDict
445
+ ) -> None:
446
+ if isinstance(info, str):
447
+ expression = info
448
+ units = None
449
+ else:
450
+ expression = info["expression"]
451
+ units = info.get("units", None)
452
+
453
+ # evaluate the expression
454
+ col = core.evaluate_output_column(
455
+ hit_table,
456
+ table_name="HITS",
457
+ expression=expression,
458
+ local_dict=local_dict,
459
+ time_dict=time_dict,
460
+ name=field,
461
+ )
462
+
463
+ if units is not None:
464
+ col.attrs["units"] = units
465
+
466
+ core.add_field_with_nesting(hit_table, field, col)
@@ -191,3 +191,4 @@ def cli(args=None) -> None:
191
191
  buffer=args.buffer,
192
192
  overwrite=args.overwrite,
193
193
  )
194
+ log.info("successfully finished post-processing")
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import contextlib
3
4
  import logging
4
5
  import time
5
6
  from typing import Any
@@ -145,11 +146,14 @@ def evaluate_output_column(
145
146
  if globals_dict == {}:
146
147
  globals_dict = None
147
148
 
149
+ ctx = contextlib.nullcontext()
148
150
  if globals_dict is not None and "pyg4ometry" in globals_dict:
149
- with utils.filter_logging(logging.CRITICAL):
150
- res = hit_table.eval(func_call, local_dict, modules=globals_dict)
151
- else:
152
- res = hit_table.eval(func_call, local_dict, modules=globals_dict)
151
+ ctx = utils.filter_logging(logging.CRITICAL)
152
+
153
+ with ctx:
154
+ res = hit_table.eval(
155
+ func_call, local_dict, modules=globals_dict, library="ak", with_units=True
156
+ )
153
157
 
154
158
  # how long did it take
155
159
  if time_dict is not None:
@@ -227,7 +231,9 @@ def get_global_objects(
227
231
  return AttrsDict(res)
228
232
 
229
233
 
230
- def get_detector_mapping(detector_mapping: dict, global_objects: AttrsDict) -> dict:
234
+ def get_detector_mapping(
235
+ detector_mapping: dict, global_objects: AttrsDict, args: AttrsDict
236
+ ) -> dict:
231
237
  """Get all the detector mapping using :func:`get_one_detector_mapping`.
232
238
 
233
239
  Parameters
@@ -236,6 +242,8 @@ def get_detector_mapping(detector_mapping: dict, global_objects: AttrsDict) -> d
236
242
  dictionary of detector mapping
237
243
  global_objects
238
244
  dictionary of global objects to use in evaluating the mapping.
245
+ args
246
+ any arguments the expression can depend on, is passed as `locals` to `eval()`.
239
247
  """
240
248
  return utils.merge_dicts(
241
249
  [
@@ -243,6 +251,7 @@ def get_detector_mapping(detector_mapping: dict, global_objects: AttrsDict) -> d
243
251
  mapping["output"],
244
252
  input_detector_name=mapping.get("input", None),
245
253
  objects=global_objects,
254
+ args=args,
246
255
  )
247
256
  for mapping in detector_mapping
248
257
  ]
@@ -253,6 +262,7 @@ def get_one_detector_mapping(
253
262
  output_detector_expression: str | list,
254
263
  objects: AttrsDict | None = None,
255
264
  input_detector_name: str | None = None,
265
+ args: AttrsDict | None = None,
256
266
  ) -> dict:
257
267
  """Extract the output detectors and the list of input to outputs by parsing the expressions.
258
268
 
@@ -282,7 +292,8 @@ def get_one_detector_mapping(
282
292
  dictionary of objects that can be referenced in the expression.
283
293
  input_detector_name
284
294
  Optional input detector name for all the outputs.
285
-
295
+ args
296
+ any arguments the expression can depend on, is passed as `locals` to `eval()`.
286
297
 
287
298
  Returns
288
299
  -------
@@ -318,7 +329,7 @@ def get_one_detector_mapping(
318
329
 
319
330
  # if no package was imported its just a name
320
331
  try:
321
- objs = evaluate_object(expression_tmp, local_dict={"OBJECTS": objects})
332
+ objs = evaluate_object(expression_tmp, local_dict={"ARGS": args, "OBJECTS": objects})
322
333
  out_names.extend(objs)
323
334
  except Exception:
324
335
  out_names.append(expression_tmp)
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+
3
+ from .core import run_daq_non_sparse
4
+
5
+ __all__ = ["run_daq_non_sparse"]