reboost 0.8.3__tar.gz → 0.8.5__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.
- {reboost-0.8.3/src/reboost.egg-info → reboost-0.8.5}/PKG-INFO +2 -2
- {reboost-0.8.3 → reboost-0.8.5}/pyproject.toml +1 -1
- reboost-0.8.5/src/reboost/__main__.py +6 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/_version.py +3 -3
- reboost-0.8.5/src/reboost/optmap/__main__.py +6 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/optmap/convolve.py +167 -20
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/optmap/evt.py +2 -2
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/optmap/mapview.py +1 -1
- reboost-0.8.5/src/reboost/spms/__init__.py +19 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/spms/pe.py +88 -4
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/utils.py +2 -2
- {reboost-0.8.3 → reboost-0.8.5/src/reboost.egg-info}/PKG-INFO +2 -2
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost.egg-info/SOURCES.txt +2 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost.egg-info/requires.txt +1 -1
- {reboost-0.8.3 → reboost-0.8.5}/tests/hit/configs/spms.yaml +8 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hit/test_build_hit.py +11 -0
- reboost-0.8.3/src/reboost/spms/__init__.py +0 -5
- {reboost-0.8.3 → reboost-0.8.5}/LICENSE +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/README.md +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/setup.cfg +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/__init__.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/build_evt.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/build_glm.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/build_hit.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/cli.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/core.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/daq/__init__.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/daq/core.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/daq/utils.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/hpge/__init__.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/hpge/psd.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/hpge/surface.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/hpge/utils.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/iterator.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/log_utils.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/math/__init__.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/math/functions.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/math/stats.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/optmap/__init__.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/optmap/cli.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/optmap/create.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/optmap/numba_pdg.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/optmap/optmap.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/profile.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/shape/__init__.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/shape/cluster.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/shape/group.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/shape/reduction.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost/units.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost.egg-info/dependency_links.txt +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost.egg-info/entry_points.txt +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost.egg-info/not-zip-safe +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/src/reboost.egg-info/top_level.txt +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/conftest.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/evt/test_evt.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/glm/test_build_glm.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hit/configs/args.yaml +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hit/configs/basic.yaml +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hit/configs/foward_only.yaml +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hit/configs/geom.gdml +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hit/configs/hit_config.yaml +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hit/configs/pars.yaml +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hit/configs/reshape.yaml +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hpge/simulation/gammas.mac +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hpge/simulation/geometry.gdml +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hpge/simulation/make_dt_map.jl +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hpge/simulation/make_geom.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hpge/test_current.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hpge/test_dt_heuristic.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hpge/test_files/drift_time_maps.lh5 +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hpge/test_files/internal_electron.lh5 +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hpge/test_hpge_map.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hpge/test_r90.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/hpge/test_surface.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/spms/test_pe.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/test_cli.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/test_core.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/test_math.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/test_optmap.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/test_optmap_dets.gdml +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/test_profile.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/test_shape.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/test_units.py +0 -0
- {reboost-0.8.3 → reboost-0.8.5}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reboost
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.5
|
|
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
|
|
@@ -28,7 +28,7 @@ Requires-Dist: scipy
|
|
|
28
28
|
Requires-Dist: numba>=0.60
|
|
29
29
|
Requires-Dist: legend-pydataobj>=1.15.1
|
|
30
30
|
Requires-Dist: legend-pygeom-optics>=0.15.0
|
|
31
|
-
Requires-Dist: legend-pygeom-tools>=0.0.
|
|
31
|
+
Requires-Dist: legend-pygeom-tools>=0.0.26
|
|
32
32
|
Requires-Dist: legend-pygeom-hpges
|
|
33
33
|
Requires-Dist: hist
|
|
34
34
|
Requires-Dist: dbetto
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.8.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 8,
|
|
31
|
+
__version__ = version = '0.8.5'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 8, 5)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g5d57bf6e0'
|
|
@@ -32,7 +32,7 @@ class OptmapForConvolve(NamedTuple):
|
|
|
32
32
|
|
|
33
33
|
def open_optmap(optmap_fn: str) -> OptmapForConvolve:
|
|
34
34
|
dets = lh5.ls(optmap_fn, "/channels/")
|
|
35
|
-
detidx = np.arange(0, dets
|
|
35
|
+
detidx = np.arange(0, len(dets))
|
|
36
36
|
|
|
37
37
|
optmap_all = lh5.read("/all/prob", optmap_fn)
|
|
38
38
|
assert isinstance(optmap_all, Histogram)
|
|
@@ -61,14 +61,14 @@ def open_optmap(optmap_fn: str) -> OptmapForConvolve:
|
|
|
61
61
|
raise ValueError(msg)
|
|
62
62
|
else:
|
|
63
63
|
detidx = np.array([OPTMAP_ANY_CH])
|
|
64
|
-
dets =
|
|
64
|
+
dets = ["all"]
|
|
65
65
|
|
|
66
66
|
# check the exponent from the optical map file
|
|
67
67
|
if "_hitcounts_exp" in lh5.ls(optmap_fn):
|
|
68
68
|
msg = "found _hitcounts_exp which is not supported any more"
|
|
69
69
|
raise RuntimeError(msg)
|
|
70
70
|
|
|
71
|
-
dets = [d.replace("/channels/", "") for d in dets]
|
|
71
|
+
dets = np.array([d.replace("/channels/", "") for d in dets])
|
|
72
72
|
|
|
73
73
|
return OptmapForConvolve(dets, detidx, optmap_edges, ow)
|
|
74
74
|
|
|
@@ -156,15 +156,70 @@ def iterate_stepwise_depositions_scintillate(
|
|
|
156
156
|
raise ValueError(msg)
|
|
157
157
|
|
|
158
158
|
rng = np.random.default_rng() if rng is None else rng
|
|
159
|
-
|
|
159
|
+
counts = ak.num(edep_hits.edep)
|
|
160
|
+
output_array = _iterate_stepwise_depositions_scintillate(
|
|
161
|
+
edep_hits, rng, scint_mat_params, mode, ak.sum(counts)
|
|
162
|
+
)
|
|
160
163
|
|
|
161
|
-
|
|
162
|
-
builder = ak.ArrayBuilder()
|
|
163
|
-
for r in output_list:
|
|
164
|
-
with builder.list():
|
|
165
|
-
builder.extend(r)
|
|
164
|
+
return ak.unflatten(output_array, counts)
|
|
166
165
|
|
|
167
|
-
|
|
166
|
+
|
|
167
|
+
def iterate_stepwise_depositions_numdet(
|
|
168
|
+
edep_hits: ak.Array,
|
|
169
|
+
optmap: OptmapForConvolve,
|
|
170
|
+
det: str,
|
|
171
|
+
map_scaling: float = 1,
|
|
172
|
+
map_scaling_sigma: float = 0,
|
|
173
|
+
rng: np.random.Generator | None = None,
|
|
174
|
+
):
|
|
175
|
+
if edep_hits.xloc.ndim == 1:
|
|
176
|
+
msg = "the pe processors only support already reshaped output"
|
|
177
|
+
raise ValueError(msg)
|
|
178
|
+
|
|
179
|
+
rng = np.random.default_rng() if rng is None else rng
|
|
180
|
+
counts = ak.num(edep_hits.num_scint_ph)
|
|
181
|
+
output_array, res = _iterate_stepwise_depositions_numdet(
|
|
182
|
+
edep_hits,
|
|
183
|
+
rng,
|
|
184
|
+
np.where(optmap.dets == det)[0][0],
|
|
185
|
+
map_scaling,
|
|
186
|
+
map_scaling_sigma,
|
|
187
|
+
optmap.edges,
|
|
188
|
+
optmap.weights,
|
|
189
|
+
ak.sum(counts),
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
if res["det_no_stats"] > 0:
|
|
193
|
+
log.warning(
|
|
194
|
+
"had edep out in voxels without stats: %d",
|
|
195
|
+
res["det_no_stats"],
|
|
196
|
+
)
|
|
197
|
+
if res["oob"] > 0:
|
|
198
|
+
log.warning(
|
|
199
|
+
"had edep out of map bounds: %d (%.2f%%)",
|
|
200
|
+
res["oob"],
|
|
201
|
+
(res["oob"] / (res["ib"] + res["oob"])) * 100,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
return ak.unflatten(output_array, counts)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def iterate_stepwise_depositions_times(
|
|
208
|
+
edep_hits: ak.Array,
|
|
209
|
+
scint_mat_params: sc.ComputedScintParams,
|
|
210
|
+
rng: np.random.Generator | None = None,
|
|
211
|
+
):
|
|
212
|
+
if edep_hits.particle.ndim == 1:
|
|
213
|
+
msg = "the pe processors only support already reshaped output"
|
|
214
|
+
raise ValueError(msg)
|
|
215
|
+
|
|
216
|
+
rng = np.random.default_rng() if rng is None else rng
|
|
217
|
+
counts = ak.sum(edep_hits.num_det_ph, axis=1)
|
|
218
|
+
output_array = _iterate_stepwise_depositions_times(
|
|
219
|
+
edep_hits, rng, scint_mat_params, ak.sum(counts)
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
return ak.unflatten(output_array, counts)
|
|
168
223
|
|
|
169
224
|
|
|
170
225
|
_pdg_func = numba_pdgid_funcs()
|
|
@@ -270,17 +325,15 @@ def _iterate_stepwise_depositions_pois(
|
|
|
270
325
|
# - cache=True does not work with outer prange, i.e. loading the cached file fails (numba bug?)
|
|
271
326
|
@njit(parallel=False, nogil=True, cache=True)
|
|
272
327
|
def _iterate_stepwise_depositions_scintillate(
|
|
273
|
-
edep_hits, rng, scint_mat_params: sc.ComputedScintParams, mode: str
|
|
328
|
+
edep_hits, rng, scint_mat_params: sc.ComputedScintParams, mode: str, output_length: int
|
|
274
329
|
):
|
|
275
330
|
pdgid_map = {}
|
|
276
|
-
|
|
331
|
+
output = np.empty(shape=output_length, dtype=np.int64)
|
|
277
332
|
|
|
333
|
+
output_index = 0
|
|
278
334
|
for rowid in range(len(edep_hits)): # iterate hits
|
|
279
335
|
hit = edep_hits[rowid]
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
# iterate steps inside the hit
|
|
283
|
-
for si in range(len(hit.particle)):
|
|
336
|
+
for si in range(len(hit.particle)): # iterate steps inside the hit
|
|
284
337
|
# get the particle information.
|
|
285
338
|
particle = hit.particle[si]
|
|
286
339
|
if particle not in pdgid_map:
|
|
@@ -295,12 +348,106 @@ def _iterate_stepwise_depositions_scintillate(
|
|
|
295
348
|
rng,
|
|
296
349
|
emission_term_model=("poisson" if mode == "no-fano" else "normal_fano"),
|
|
297
350
|
)
|
|
298
|
-
|
|
351
|
+
output[output_index] = num_phot
|
|
352
|
+
output_index += 1
|
|
299
353
|
|
|
300
|
-
|
|
301
|
-
|
|
354
|
+
assert output_index == output_length
|
|
355
|
+
return output
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
# - run with NUMBA_FULL_TRACEBACKS=1 NUMBA_BOUNDSCHECK=1 for testing/checking
|
|
359
|
+
# - cache=True does not work with outer prange, i.e. loading the cached file fails (numba bug?)
|
|
360
|
+
@njit(parallel=False, nogil=True, cache=True)
|
|
361
|
+
def _iterate_stepwise_depositions_numdet(
|
|
362
|
+
edep_hits,
|
|
363
|
+
rng,
|
|
364
|
+
detidx: int,
|
|
365
|
+
map_scaling: float,
|
|
366
|
+
map_scaling_sigma: float,
|
|
367
|
+
optmap_edges,
|
|
368
|
+
optmap_weights,
|
|
369
|
+
output_length: int,
|
|
370
|
+
):
|
|
371
|
+
oob = ib = det_no_stats = 0
|
|
372
|
+
output = np.empty(shape=output_length, dtype=np.int64)
|
|
373
|
+
|
|
374
|
+
output_index = 0
|
|
375
|
+
for rowid in range(len(edep_hits)): # iterate hits
|
|
376
|
+
hit = edep_hits[rowid]
|
|
377
|
+
|
|
378
|
+
map_scaling_evt = map_scaling
|
|
379
|
+
if map_scaling_sigma > 0:
|
|
380
|
+
map_scaling_evt = rng.normal(loc=map_scaling, scale=map_scaling_sigma)
|
|
381
|
+
|
|
382
|
+
# iterate steps inside the hit
|
|
383
|
+
for si in range(len(hit.xloc)):
|
|
384
|
+
loc = np.array([hit.xloc[si], hit.yloc[si], hit.zloc[si]], dtype=np.float64)
|
|
385
|
+
# coordinates -> bins of the optical map.
|
|
386
|
+
bins = np.empty(3, dtype=np.int64)
|
|
387
|
+
for j in range(3):
|
|
388
|
+
edges = optmap_edges[j].astype(np.float64)
|
|
389
|
+
start = edges[0]
|
|
390
|
+
width = edges[1] - edges[0]
|
|
391
|
+
nbins = edges.shape[0] - 1
|
|
392
|
+
bins[j] = int((loc[j] - start) / width)
|
|
393
|
+
|
|
394
|
+
if bins[j] < 0 or bins[j] >= nbins:
|
|
395
|
+
bins[j] = -1 # normalize all out-of-bounds bins just to one end.
|
|
396
|
+
|
|
397
|
+
if bins[0] == -1 or bins[1] == -1 or bins[2] == -1:
|
|
398
|
+
detp = 0.0 # out-of-bounds of optmap
|
|
399
|
+
oob += 1
|
|
400
|
+
else:
|
|
401
|
+
# get probabilities from map.
|
|
402
|
+
detp = optmap_weights[detidx, bins[0], bins[1], bins[2]] * map_scaling_evt
|
|
403
|
+
if detp < 0:
|
|
404
|
+
det_no_stats += 1
|
|
405
|
+
ib += 1
|
|
406
|
+
|
|
407
|
+
pois_cnt = 0 if detp <= 0.0 else rng.poisson(lam=hit.num_scint_ph[si] * detp)
|
|
408
|
+
output[output_index] = pois_cnt
|
|
409
|
+
output_index += 1
|
|
410
|
+
|
|
411
|
+
assert output_index == output_length
|
|
412
|
+
return output, {"oob": oob, "ib": ib, "det_no_stats": det_no_stats}
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
# - run with NUMBA_FULL_TRACEBACKS=1 NUMBA_BOUNDSCHECK=1 for testing/checking
|
|
416
|
+
# - cache=True does not work with outer prange, i.e. loading the cached file fails (numba bug?)
|
|
417
|
+
# - the output dictionary is not threadsafe, so parallel=True is not working with it.
|
|
418
|
+
@njit(parallel=False, nogil=True, cache=True)
|
|
419
|
+
def _iterate_stepwise_depositions_times(
|
|
420
|
+
edep_hits, rng, scint_mat_params: sc.ComputedScintParams, output_length: int
|
|
421
|
+
):
|
|
422
|
+
pdgid_map = {}
|
|
423
|
+
output = np.empty(shape=output_length, dtype=np.float64)
|
|
424
|
+
|
|
425
|
+
output_index = 0
|
|
426
|
+
for rowid in range(len(edep_hits)): # iterate hits
|
|
427
|
+
hit = edep_hits[rowid]
|
|
428
|
+
|
|
429
|
+
assert len(hit.particle) == len(hit.num_det_ph)
|
|
430
|
+
# iterate steps inside the hit
|
|
431
|
+
for si in range(len(hit.particle)):
|
|
432
|
+
pois_cnt = hit.num_det_ph[si]
|
|
433
|
+
if pois_cnt <= 0:
|
|
434
|
+
continue
|
|
435
|
+
|
|
436
|
+
# get the particle information.
|
|
437
|
+
particle = hit.particle[si]
|
|
438
|
+
if particle not in pdgid_map:
|
|
439
|
+
pdgid_map[particle] = (_pdgid_to_particle(particle), _pdg_func.charge(particle))
|
|
440
|
+
part, _charge = pdgid_map[particle]
|
|
441
|
+
|
|
442
|
+
# get time spectrum.
|
|
443
|
+
# note: we assume "immediate" propagation after scintillation.
|
|
444
|
+
scint_times = sc.scintillate_times(scint_mat_params, part, pois_cnt, rng) + hit.time[si]
|
|
445
|
+
assert len(scint_times) == pois_cnt
|
|
446
|
+
output[output_index : output_index + len(scint_times)] = scint_times
|
|
447
|
+
output_index += len(scint_times)
|
|
302
448
|
|
|
303
|
-
|
|
449
|
+
assert output_index == output_length
|
|
450
|
+
return output
|
|
304
451
|
|
|
305
452
|
|
|
306
453
|
def _get_scint_params(material: str):
|
|
@@ -131,9 +131,9 @@ def get_optical_detectors_from_geom(geom_fn) -> dict[int, str]:
|
|
|
131
131
|
import pygeomtools
|
|
132
132
|
|
|
133
133
|
geom_registry = pyg4ometry.gdml.Reader(geom_fn).getRegistry()
|
|
134
|
-
detectors = pygeomtools.get_all_sensvols(geom_registry)
|
|
134
|
+
detectors = pygeomtools.get_all_sensvols(geom_registry, type_filter="optical")
|
|
135
135
|
return OrderedDict(
|
|
136
|
-
[(d.uid, name) for name, d in detectors.items()
|
|
136
|
+
[(d.uid, d.ntuple_name if d.ntuple_name else name) for name, d in detectors.items()]
|
|
137
137
|
)
|
|
138
138
|
|
|
139
139
|
|
|
@@ -95,7 +95,7 @@ def _read_data(
|
|
|
95
95
|
histogram_choice: str = "prob",
|
|
96
96
|
) -> tuple[tuple[NDArray], NDArray]:
|
|
97
97
|
histogram = histogram_choice if histogram_choice != "prob_unc_rel" else "prob"
|
|
98
|
-
detid = f"channels/{detid}" if detid != all and not detid.startswith("channels/") else detid
|
|
98
|
+
detid = f"channels/{detid}" if detid != "all" and not detid.startswith("channels/") else detid
|
|
99
99
|
|
|
100
100
|
optmap_all = lh5.read(f"/{detid}/{histogram}", optmap_fn)
|
|
101
101
|
optmap_edges = tuple([b.edges for b in optmap_all.binning])
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from .pe import (
|
|
4
|
+
detected_photoelectrons,
|
|
5
|
+
emitted_scintillation_photons,
|
|
6
|
+
load_optmap,
|
|
7
|
+
load_optmap_all,
|
|
8
|
+
number_of_detected_photoelectrons,
|
|
9
|
+
photoelectron_times,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"detected_photoelectrons",
|
|
14
|
+
"emitted_scintillation_photons",
|
|
15
|
+
"load_optmap",
|
|
16
|
+
"load_optmap_all",
|
|
17
|
+
"number_of_detected_photoelectrons",
|
|
18
|
+
"photoelectron_times",
|
|
19
|
+
]
|
|
@@ -109,7 +109,12 @@ def detected_photoelectrons(
|
|
|
109
109
|
map_scaling: float = 1,
|
|
110
110
|
map_scaling_sigma: float = 0,
|
|
111
111
|
) -> VectorOfVectors:
|
|
112
|
-
"""Derive the number of detected photoelectrons (p.e.) from scintillator hits using an optical map.
|
|
112
|
+
"""Derive the number and arrival times of detected photoelectrons (p.e.) from scintillator hits using an optical map.
|
|
113
|
+
|
|
114
|
+
.. deprecated :: 0.8.5
|
|
115
|
+
Use the other, more fine-granular and split processors
|
|
116
|
+
:func:`number_of_detected_photoelectrons` and :func:`photoelectron_times` to
|
|
117
|
+
replace this legacy processor.
|
|
113
118
|
|
|
114
119
|
Parameters
|
|
115
120
|
----------
|
|
@@ -140,8 +145,8 @@ def detected_photoelectrons(
|
|
|
140
145
|
"""
|
|
141
146
|
hits = ak.Array(
|
|
142
147
|
{
|
|
143
|
-
"num_scint_ph": num_scint_ph,
|
|
144
|
-
"particle": particle,
|
|
148
|
+
"num_scint_ph": units_conv_ak(num_scint_ph, "dimensionless"),
|
|
149
|
+
"particle": units_conv_ak(particle, "dimensionless"),
|
|
145
150
|
"time": units_conv_ak(time, "ns"),
|
|
146
151
|
"xloc": units_conv_ak(xloc, "m"),
|
|
147
152
|
"yloc": units_conv_ak(yloc, "m"),
|
|
@@ -171,8 +176,87 @@ def emitted_scintillation_photons(
|
|
|
171
176
|
material
|
|
172
177
|
scintillating material name.
|
|
173
178
|
"""
|
|
174
|
-
hits = ak.Array(
|
|
179
|
+
hits = ak.Array(
|
|
180
|
+
{
|
|
181
|
+
"edep": units_conv_ak(edep, "keV"),
|
|
182
|
+
"particle": units_conv_ak(particle, "dimensionless"),
|
|
183
|
+
}
|
|
184
|
+
)
|
|
175
185
|
|
|
176
186
|
scint_mat_params = convolve._get_scint_params(material)
|
|
177
187
|
ph = convolve.iterate_stepwise_depositions_scintillate(hits, scint_mat_params)
|
|
178
188
|
return VectorOfVectors(ph)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def number_of_detected_photoelectrons(
|
|
192
|
+
xloc: ak.Array,
|
|
193
|
+
yloc: ak.Array,
|
|
194
|
+
zloc: ak.Array,
|
|
195
|
+
num_scint_ph: ak.Array,
|
|
196
|
+
optmap: convolve.OptmapForConvolve,
|
|
197
|
+
spm_detector: str,
|
|
198
|
+
map_scaling: float = 1,
|
|
199
|
+
map_scaling_sigma: float = 0,
|
|
200
|
+
) -> VectorOfVectors:
|
|
201
|
+
"""Derive the number of detected photoelectrons (p.e.) from scintillator hits using an optical map.
|
|
202
|
+
|
|
203
|
+
Parameters
|
|
204
|
+
----------
|
|
205
|
+
xloc
|
|
206
|
+
array of x coordinate position of scintillation events.
|
|
207
|
+
yloc
|
|
208
|
+
array of y coordinate position of scintillation events.
|
|
209
|
+
zloc
|
|
210
|
+
array of z coordinate position of scintillation events.
|
|
211
|
+
num_scint_ph
|
|
212
|
+
array of emitted scintillation photons, as generated by
|
|
213
|
+
:func:`emitted_scintillation_photons`.
|
|
214
|
+
detp
|
|
215
|
+
"""
|
|
216
|
+
hits = ak.Array(
|
|
217
|
+
{
|
|
218
|
+
"xloc": units_conv_ak(xloc, "m"),
|
|
219
|
+
"yloc": units_conv_ak(yloc, "m"),
|
|
220
|
+
"zloc": units_conv_ak(zloc, "m"),
|
|
221
|
+
"num_scint_ph": units_conv_ak(num_scint_ph, "dimensionless"),
|
|
222
|
+
}
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
ph = convolve.iterate_stepwise_depositions_numdet(
|
|
226
|
+
hits, optmap, spm_detector, map_scaling, map_scaling_sigma
|
|
227
|
+
)
|
|
228
|
+
return VectorOfVectors(ph)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def photoelectron_times(
|
|
232
|
+
num_det_ph: ak.Array,
|
|
233
|
+
particle: ak.Array,
|
|
234
|
+
time: ak.Array,
|
|
235
|
+
material: str,
|
|
236
|
+
) -> VectorOfVectors:
|
|
237
|
+
"""Derive the arrival times of scintillation photons.
|
|
238
|
+
|
|
239
|
+
Parameters
|
|
240
|
+
----------
|
|
241
|
+
num_det_ph
|
|
242
|
+
array of detected scintillation photons, as generated by
|
|
243
|
+
:func:`emitted_scintillation_photons`.
|
|
244
|
+
particle
|
|
245
|
+
array of particle PDG IDs of scintillation events.
|
|
246
|
+
time
|
|
247
|
+
array of timestamps of scintillation events.
|
|
248
|
+
material
|
|
249
|
+
scintillating material name.
|
|
250
|
+
"""
|
|
251
|
+
hits = ak.Array(
|
|
252
|
+
{
|
|
253
|
+
"num_det_ph": units_conv_ak(num_det_ph, "dimensionless"),
|
|
254
|
+
"particle": units_conv_ak(particle, "dimensionless"),
|
|
255
|
+
"time": units_conv_ak(time, "ns"),
|
|
256
|
+
}
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
scint_mat_params = convolve._get_scint_params(material)
|
|
260
|
+
pe = convolve.iterate_stepwise_depositions_times(hits, scint_mat_params)
|
|
261
|
+
|
|
262
|
+
return VectorOfVectors(pe, attrs={"units": "ns"})
|
|
@@ -445,7 +445,7 @@ def write_lh5(
|
|
|
445
445
|
time_dict.update_field("write", start_time)
|
|
446
446
|
|
|
447
447
|
|
|
448
|
-
def get_remage_detector_uids(h5file: str | Path) -> dict:
|
|
448
|
+
def get_remage_detector_uids(h5file: str | Path, *, lh5_table: str = "stp") -> dict:
|
|
449
449
|
"""Get mapping of detector names to UIDs from a remage output file.
|
|
450
450
|
|
|
451
451
|
The remage LH5 output files contain a link structure that lets the user
|
|
@@ -483,7 +483,7 @@ def get_remage_detector_uids(h5file: str | Path) -> dict:
|
|
|
483
483
|
|
|
484
484
|
out = {}
|
|
485
485
|
with h5py.File(h5file, "r") as f:
|
|
486
|
-
g = f["/
|
|
486
|
+
g = f[f"/{lh5_table}/__by_uid__"]
|
|
487
487
|
# loop over links
|
|
488
488
|
for key in g:
|
|
489
489
|
# is this a link?
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reboost
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.5
|
|
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
|
|
@@ -28,7 +28,7 @@ Requires-Dist: scipy
|
|
|
28
28
|
Requires-Dist: numba>=0.60
|
|
29
29
|
Requires-Dist: legend-pydataobj>=1.15.1
|
|
30
30
|
Requires-Dist: legend-pygeom-optics>=0.15.0
|
|
31
|
-
Requires-Dist: legend-pygeom-tools>=0.0.
|
|
31
|
+
Requires-Dist: legend-pygeom-tools>=0.0.26
|
|
32
32
|
Requires-Dist: legend-pygeom-hpges
|
|
33
33
|
Requires-Dist: hist
|
|
34
34
|
Requires-Dist: dbetto
|
|
@@ -2,6 +2,7 @@ LICENSE
|
|
|
2
2
|
README.md
|
|
3
3
|
pyproject.toml
|
|
4
4
|
src/reboost/__init__.py
|
|
5
|
+
src/reboost/__main__.py
|
|
5
6
|
src/reboost/_version.py
|
|
6
7
|
src/reboost/build_evt.py
|
|
7
8
|
src/reboost/build_glm.py
|
|
@@ -31,6 +32,7 @@ src/reboost/math/__init__.py
|
|
|
31
32
|
src/reboost/math/functions.py
|
|
32
33
|
src/reboost/math/stats.py
|
|
33
34
|
src/reboost/optmap/__init__.py
|
|
35
|
+
src/reboost/optmap/__main__.py
|
|
34
36
|
src/reboost/optmap/cli.py
|
|
35
37
|
src/reboost/optmap/convolve.py
|
|
36
38
|
src/reboost/optmap/create.py
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
objects:
|
|
2
2
|
spms: "['S001', 'S002']"
|
|
3
|
+
optmap_test: reboost.spms.load_optmap_all(ARGS.optmap_path)
|
|
3
4
|
|
|
4
5
|
processing_groups:
|
|
5
6
|
- name: spms
|
|
@@ -14,6 +15,7 @@ processing_groups:
|
|
|
14
15
|
- edep
|
|
15
16
|
- pe_times
|
|
16
17
|
- pe_times_lar
|
|
18
|
+
- pe_times_lar_full
|
|
17
19
|
|
|
18
20
|
pre_operations:
|
|
19
21
|
num_scint_ph:
|
|
@@ -24,7 +26,13 @@ processing_groups:
|
|
|
24
26
|
optmap_lar: reboost.spms.load_optmap(ARGS.optmap_path, DETECTOR)
|
|
25
27
|
|
|
26
28
|
operations:
|
|
29
|
+
num_det_ph: reboost.spms.number_of_detected_photoelectrons(
|
|
30
|
+
HITS.xloc, HITS.yloc, HITS.zloc, HITS.num_scint_ph,
|
|
31
|
+
DETECTOR_OBJECTS.optmap_lar, DETECTOR)
|
|
27
32
|
pe_times_lar:
|
|
33
|
+
reboost.spms.photoelectron_times(HITS.num_det_ph, HITS.particle,
|
|
34
|
+
HITS.time, "lar")
|
|
35
|
+
pe_times_lar_full:
|
|
28
36
|
reboost.spms.detected_photoelectrons( HITS.num_scint_ph, HITS.particle,
|
|
29
37
|
HITS.time, HITS.xloc, HITS.yloc, HITS.zloc, DETECTOR_OBJECTS.optmap_lar,
|
|
30
38
|
"lar", DETECTOR )
|
|
@@ -6,6 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
import awkward as ak
|
|
7
7
|
import dbetto
|
|
8
8
|
import h5py
|
|
9
|
+
import numpy as np
|
|
9
10
|
import pytest
|
|
10
11
|
from lgdo import Array, Struct, Table, VectorOfVectors, lh5
|
|
11
12
|
|
|
@@ -333,6 +334,7 @@ def test_spms(test_gen_lh5_scint, tmptestdir):
|
|
|
333
334
|
m.create_probability()
|
|
334
335
|
m.write_lh5(map_file, "channels/S001", "overwrite_file")
|
|
335
336
|
m.write_lh5(map_file, "channels/S002", "write_safe")
|
|
337
|
+
m.write_lh5(map_file, "all", "write_safe")
|
|
336
338
|
|
|
337
339
|
outfile = f"{tmptestdir}/spms_hit.lh5"
|
|
338
340
|
reboost.build_hit(
|
|
@@ -349,3 +351,12 @@ def test_spms(test_gen_lh5_scint, tmptestdir):
|
|
|
349
351
|
assert "S002" in hits
|
|
350
352
|
|
|
351
353
|
assert isinstance(hits["S001"]["pe_times_lar"], VectorOfVectors)
|
|
354
|
+
assert isinstance(hits["S001"]["pe_times_lar_full"], VectorOfVectors)
|
|
355
|
+
|
|
356
|
+
pe_split = hits["S001"]["pe_times_lar"].view_as("ak")
|
|
357
|
+
pe_full = hits["S001"]["pe_times_lar_full"].view_as("ak")
|
|
358
|
+
pe_ratio = ak.count(pe_split) / ak.count(pe_full)
|
|
359
|
+
|
|
360
|
+
assert np.abs(pe_ratio - 1) < 0.1
|
|
361
|
+
|
|
362
|
+
# TODO: test they are statistically close
|
|
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
|
|
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
|