legend-dataflow-scripts 0.1.2__py3-none-any.whl → 0.1.3__py3-none-any.whl
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.
- {legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.3.dist-info}/METADATA +2 -2
- {legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.3.dist-info}/RECORD +12 -11
- {legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.3.dist-info}/WHEEL +1 -1
- legenddataflowscripts/_version.py +2 -2
- legenddataflowscripts/par/geds/dsp/pz.py +2 -2
- legenddataflowscripts/par/geds/hit/aoe.py +190 -109
- legenddataflowscripts/par/geds/hit/lq.py +198 -76
- legenddataflowscripts/par/geds/hit/qc.py +127 -91
- legenddataflowscripts/utils/__init__.py +2 -0
- legenddataflowscripts/utils/plot_dict.py +13 -0
- {legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.3.dist-info}/entry_points.txt +0 -0
- {legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.3.dist-info}/top_level.txt +0 -0
{legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.3.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: legend-dataflow-scripts
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Python package for the processing scripts for LEGEND-200 data
|
|
5
5
|
Author-email: George Marshall <ggmarsh@uw.edu>, Luigi Pertoldi <gipert@pm.me>
|
|
6
6
|
Maintainer: The LEGEND Collaboration
|
|
@@ -23,7 +23,7 @@ Requires-Dist: pygama>=2.1
|
|
|
23
23
|
Requires-Dist: dspeed>=1.6
|
|
24
24
|
Requires-Dist: pylegendmeta>=1.2.5
|
|
25
25
|
Requires-Dist: legend-pydataobj>=1.11
|
|
26
|
-
Requires-Dist: legend-daq2lh5>=1.
|
|
26
|
+
Requires-Dist: legend-daq2lh5>=1.6.1
|
|
27
27
|
Requires-Dist: pip
|
|
28
28
|
Provides-Extra: test
|
|
29
29
|
Requires-Dist: legend-dataflow-scripts; extra == "test"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
legenddataflowscripts/__init__.py,sha256=hlpvTxSBjOyXlZUyOyYx3VwT5LS6zNzhAZnTmfT3NjU,303
|
|
2
|
-
legenddataflowscripts/_version.py,sha256=
|
|
2
|
+
legenddataflowscripts/_version.py,sha256=NIzzV8ZM0W-CSLuEs1weG4zPrn_-8yr1AwwI1iuS6yo,511
|
|
3
3
|
legenddataflowscripts/par/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
legenddataflowscripts/par/geds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
legenddataflowscripts/par/geds/dsp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -7,30 +7,31 @@ legenddataflowscripts/par/geds/dsp/dplms.py,sha256=OOvnN_OcU046zhuyNTGxcmGYLCZ7Y
|
|
|
7
7
|
legenddataflowscripts/par/geds/dsp/eopt.py,sha256=UklMozVw57X8EhOVjOxwKSXtuHkX45iJ2YMLx69TQps,13680
|
|
8
8
|
legenddataflowscripts/par/geds/dsp/evtsel.py,sha256=qheFqGezjRxW9UNf9DV1n8VuZjCLGZT-WaWyhrfgPJ4,16485
|
|
9
9
|
legenddataflowscripts/par/geds/dsp/nopt.py,sha256=K7R4OBfO0wek03VvhBoYXDP7lURi_Xoph9Kb3iMkfx4,4263
|
|
10
|
-
legenddataflowscripts/par/geds/dsp/pz.py,sha256=
|
|
10
|
+
legenddataflowscripts/par/geds/dsp/pz.py,sha256=sucYUtsgWKYtR-GbmRh5b61EYHqNRMWGckD3DJdHUvs,8273
|
|
11
11
|
legenddataflowscripts/par/geds/dsp/svm.py,sha256=eDneRB_PQZp8Q4n2VheTX3kbu4ufZQ-jnuCCjvtwFpk,826
|
|
12
12
|
legenddataflowscripts/par/geds/dsp/svm_build.py,sha256=8K0NUpQqL2HUWRKjMpM5H-TienVPUzIuKED94ZZnIzA,2227
|
|
13
13
|
legenddataflowscripts/par/geds/hit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
-
legenddataflowscripts/par/geds/hit/aoe.py,sha256=
|
|
14
|
+
legenddataflowscripts/par/geds/hit/aoe.py,sha256=4sXRz6UaPD7phihAO3_C42l7fJT8UrhhOZswzO8rAqw,11387
|
|
15
15
|
legenddataflowscripts/par/geds/hit/ecal.py,sha256=tsIL9FP-aXgM2B1K8ygjcsLeNZ9Yv7je84fT-K7m3vQ,26194
|
|
16
|
-
legenddataflowscripts/par/geds/hit/lq.py,sha256=
|
|
17
|
-
legenddataflowscripts/par/geds/hit/qc.py,sha256=
|
|
16
|
+
legenddataflowscripts/par/geds/hit/lq.py,sha256=td0qVvVRwYbhiA-IhAZYLgTdW6xpTeeE3mrSoWeLw2U,11307
|
|
17
|
+
legenddataflowscripts/par/geds/hit/qc.py,sha256=6PpA6aVjd9Gysfz_up7cuWw-ftwDA8F8gNKBcPPq4lc,12409
|
|
18
18
|
legenddataflowscripts/tier/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
legenddataflowscripts/tier/dsp.py,sha256=J_ABEqbQurZHJOg8LV2aporNjZQpPg2bDZG6DkmuAL4,8633
|
|
20
20
|
legenddataflowscripts/tier/hit.py,sha256=-LCfsqYAYPAuN2OKbPuh4G2P5B4uA4YmQGcqUtbZxis,4989
|
|
21
|
-
legenddataflowscripts/utils/__init__.py,sha256=
|
|
21
|
+
legenddataflowscripts/utils/__init__.py,sha256=NPpxqapio8CeQIbG8gYnz-OPoUbOlDT6tjXV-lJrKWc,426
|
|
22
22
|
legenddataflowscripts/utils/alias_table.py,sha256=e0wRiDcpje8VVr_PlcbkA0kPz0qSGpGX4vJ3tfGefMA,742
|
|
23
23
|
legenddataflowscripts/utils/cfgtools.py,sha256=_1yxw_eJ08AihONhJ9sWet5HQZpOagj8Yg8y9LS3zX4,381
|
|
24
24
|
legenddataflowscripts/utils/convert_np.py,sha256=8q_K3w3jAREG-9CJlErP3Vca0OYTYAYJIK4g_TClvBU,819
|
|
25
25
|
legenddataflowscripts/utils/log.py,sha256=5v8J7PZJHHoSy12w9e9DkYmqdPvYXj6YfVaMbhvX614,2230
|
|
26
|
+
legenddataflowscripts/utils/plot_dict.py,sha256=-wfJC5U9OTE1Asazz64kT5Ta008w6UJmDSsr3YAubRM,449
|
|
26
27
|
legenddataflowscripts/utils/pulser_removal.py,sha256=kuARdp1jf-lsUWcb0_KRDp-ZXzkHNrDCXUc3h7TJm7Q,424
|
|
27
28
|
legenddataflowscripts/workflow/__init__.py,sha256=p-57OklNpVYqwMaLctLO8zMvhpXaTILkd3j4CaS_Juk,394
|
|
28
29
|
legenddataflowscripts/workflow/execenv.py,sha256=O6Z6EH6Yp0JXnwX2wTzduHC9Q9gu-_d1RuuE2pQ5caE,9061
|
|
29
30
|
legenddataflowscripts/workflow/filedb.py,sha256=rbvOcXUxLbHz177QuDIDAL3aysz-bZDjHOiMsRHssZo,3434
|
|
30
31
|
legenddataflowscripts/workflow/pre_compile_catalog.py,sha256=cEK0KXh-ClSE2Bo9MK471o79XG22bMY5r-2tIihtCfk,790
|
|
31
32
|
legenddataflowscripts/workflow/utils.py,sha256=eKE8KIG2ffynZt9fTbI1SVQV85i3aW9GFGh1Nio1iDo,3118
|
|
32
|
-
legend_dataflow_scripts-0.1.
|
|
33
|
-
legend_dataflow_scripts-0.1.
|
|
34
|
-
legend_dataflow_scripts-0.1.
|
|
35
|
-
legend_dataflow_scripts-0.1.
|
|
36
|
-
legend_dataflow_scripts-0.1.
|
|
33
|
+
legend_dataflow_scripts-0.1.3.dist-info/METADATA,sha256=ajopD8KYE0gSC2mRkgv3Dc4SCkb5MFc8vhRMLh9WH9A,3122
|
|
34
|
+
legend_dataflow_scripts-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
35
|
+
legend_dataflow_scripts-0.1.3.dist-info/entry_points.txt,sha256=B197waSm-orA_ZS-9rkxNDsmOHdCn8CbWodnlqXQKRg,1313
|
|
36
|
+
legend_dataflow_scripts-0.1.3.dist-info/top_level.txt,sha256=s8E2chjJNYUbrN6whFG_VCsJKySFp1IOXLcUefA7DB0,22
|
|
37
|
+
legend_dataflow_scripts-0.1.3.dist-info/RECORD,,
|
|
@@ -181,14 +181,14 @@ def par_geds_dsp_pz() -> None:
|
|
|
181
181
|
|
|
182
182
|
plot_dict = tau.plot_waveforms_after_correction(
|
|
183
183
|
tb_data,
|
|
184
|
-
kwarg_dict("wf_pz_field", "wf_pz"),
|
|
184
|
+
kwarg_dict.get("wf_pz_field", "wf_pz"),
|
|
185
185
|
norm_param=kwarg_dict.get("norm_param", "pz_mean"),
|
|
186
186
|
xlim=[0, len(tb_data[kwarg_dict["wf_field"]]["values"].nda[0])],
|
|
187
187
|
)
|
|
188
188
|
|
|
189
189
|
zoomed = tau.plot_waveforms_after_correction(
|
|
190
190
|
tb_data,
|
|
191
|
-
kwarg_dict("wf_pz_field", "wf_pz"),
|
|
191
|
+
kwarg_dict.get("wf_pz_field", "wf_pz"),
|
|
192
192
|
norm_param=kwarg_dict.get("norm_param", "pz_mean"),
|
|
193
193
|
xlim=[400, len(tb_data[kwarg_dict["wf_field"]]["values"].nda[0])],
|
|
194
194
|
ylim=[0.8, 1.1],
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
+
import copy
|
|
5
|
+
import logging
|
|
4
6
|
import pickle as pkl
|
|
7
|
+
import re
|
|
8
|
+
import time
|
|
5
9
|
import warnings
|
|
6
10
|
from pathlib import Path
|
|
7
11
|
|
|
@@ -9,42 +13,172 @@ import numpy as np
|
|
|
9
13
|
from dbetto import TextDB
|
|
10
14
|
from dbetto.catalog import Props
|
|
11
15
|
from pygama.pargen.AoE_cal import * # noqa: F403
|
|
12
|
-
from pygama.pargen.AoE_cal import CalAoE
|
|
16
|
+
from pygama.pargen.AoE_cal import CalAoE
|
|
13
17
|
from pygama.pargen.utils import load_data
|
|
14
18
|
|
|
15
19
|
from ....utils import (
|
|
16
20
|
build_log,
|
|
17
21
|
convert_dict_np_to_float,
|
|
22
|
+
fill_plot_dict,
|
|
18
23
|
get_pulser_mask,
|
|
19
24
|
)
|
|
20
25
|
|
|
26
|
+
log = logging.getLogger(__name__)
|
|
27
|
+
|
|
21
28
|
warnings.filterwarnings(action="ignore", category=RuntimeWarning)
|
|
22
29
|
|
|
23
30
|
|
|
24
31
|
def get_results_dict(aoe_class):
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
result_dict = {}
|
|
33
|
+
for tstamp in aoe_class.low_side_sfs_by_run:
|
|
34
|
+
result_dict[tstamp] = {
|
|
35
|
+
"cal_energy_param": aoe_class.cal_energy_param,
|
|
36
|
+
"dt_param": aoe_class.dt_param,
|
|
37
|
+
"rt_correction": aoe_class.dt_corr,
|
|
38
|
+
"1000-1300keV": aoe_class.timecorr_df.to_dict("index"),
|
|
39
|
+
"correction_fit_results": aoe_class.energy_corr_res_dict,
|
|
40
|
+
"low_cut": aoe_class.low_cut_val,
|
|
41
|
+
"high_cut": aoe_class.high_cut_val,
|
|
42
|
+
"low_side_sfs": aoe_class.low_side_sfs.to_dict("index"),
|
|
43
|
+
"2_side_sfs": aoe_class.two_side_sfs.to_dict("index"),
|
|
44
|
+
"low_side_sfs_by_run": aoe_class.low_side_sfs_by_run[tstamp].to_dict(
|
|
45
|
+
"index"
|
|
46
|
+
),
|
|
47
|
+
"2_side_sfs_by_run": aoe_class.two_side_sfs_by_run[tstamp].to_dict("index"),
|
|
48
|
+
}
|
|
49
|
+
return result_dict
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def run_aoe_calibration(
|
|
53
|
+
data,
|
|
54
|
+
cal_dicts,
|
|
55
|
+
results_dicts,
|
|
56
|
+
object_dicts,
|
|
57
|
+
plot_dicts,
|
|
58
|
+
config,
|
|
59
|
+
debug_mode=False,
|
|
60
|
+
):
|
|
61
|
+
if isinstance(config, str | list):
|
|
62
|
+
config = Props.read_from(config)
|
|
63
|
+
|
|
64
|
+
if config.get("run_aoe", True) is True:
|
|
65
|
+
if "plot_options" in config:
|
|
66
|
+
for field, item in config["plot_options"].items():
|
|
67
|
+
config["plot_options"][field]["function"] = eval(item["function"])
|
|
68
|
+
|
|
69
|
+
if "dt_cut" in config and config["dt_cut"] is not None:
|
|
70
|
+
cut_dict = config["dt_cut"]["cut"]
|
|
71
|
+
for tstamp in cal_dicts:
|
|
72
|
+
cal_dicts[tstamp].update(cut_dict)
|
|
73
|
+
|
|
74
|
+
exp = cut_dict[next(iter(cut_dict))]["expression"]
|
|
75
|
+
for key in cut_dict[next(iter(cut_dict))]["parameters"]:
|
|
76
|
+
exp = re.sub(f"(?<![a-zA-Z0-9]){key}(?![a-zA-Z0-9])", f"@{key}", exp)
|
|
77
|
+
data[next(iter(cut_dict))] = data.eval(
|
|
78
|
+
exp, local_dict=cut_dict[next(iter(cut_dict))]["parameters"]
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
eres = copy.deepcopy(
|
|
83
|
+
results_dicts[next(iter(results_dicts))]["partition_ecal"][
|
|
84
|
+
config["cal_energy_param"]
|
|
85
|
+
]["eres_linear"]
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def eres_func(x):
|
|
89
|
+
return eval(eres["expression"], dict(x=x, **eres["parameters"]))
|
|
90
|
+
|
|
91
|
+
if np.isnan(eres_func(2000)):
|
|
92
|
+
raise RuntimeError
|
|
93
|
+
except (KeyError, RuntimeError):
|
|
94
|
+
try:
|
|
95
|
+
eres = copy.deepcopy(
|
|
96
|
+
results_dicts[next(iter(results_dicts))]["ecal"][
|
|
97
|
+
config["cal_energy_param"]
|
|
98
|
+
]["eres_linear"]
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def eres_func(x):
|
|
102
|
+
return eval(eres["expression"], dict(x=x, **eres["parameters"]))
|
|
103
|
+
|
|
104
|
+
except KeyError:
|
|
105
|
+
|
|
106
|
+
def eres_func(x):
|
|
107
|
+
return x * np.nan
|
|
108
|
+
|
|
109
|
+
data["AoE_Uncorr"] = (
|
|
110
|
+
data[config["current_param"]] / data[config["energy_param"]]
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
start = time.time()
|
|
114
|
+
log.info("calibrating A/E")
|
|
115
|
+
|
|
116
|
+
aoe = CalAoE(
|
|
117
|
+
cal_dicts=cal_dicts,
|
|
118
|
+
cal_energy_param=config["cal_energy_param"],
|
|
119
|
+
eres_func=eres_func,
|
|
120
|
+
pdf=eval(config.get("pdf", "aoe_peak")),
|
|
121
|
+
mean_func=eval(config.get("mean_func", "Pol1")),
|
|
122
|
+
sigma_func=eval(config.get("sigma_func", "SigmaFit")),
|
|
123
|
+
selection_string=f"{config['cut_field']}&(~is_pulser)",
|
|
124
|
+
dt_corr=config.get("dt_corr", False),
|
|
125
|
+
dep_correct=config.get("dep_correct", False),
|
|
126
|
+
dt_cut=config.get("dt_cut", None),
|
|
127
|
+
dt_param=config.get("dt_param", 3),
|
|
128
|
+
high_cut_val=config.get("high_cut_val", 3),
|
|
129
|
+
compt_bands_width=config.get("debug_mode", 20),
|
|
130
|
+
debug_mode=debug_mode | config.get("debug_mode", False),
|
|
131
|
+
)
|
|
132
|
+
aoe.update_cal_dicts(
|
|
133
|
+
{
|
|
134
|
+
"AoE_Uncorr": {
|
|
135
|
+
"expression": f"{config['current_param']}/{config['energy_param']}",
|
|
136
|
+
"parameters": {},
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
)
|
|
140
|
+
aoe.calibrate(data, "AoE_Uncorr")
|
|
36
141
|
|
|
142
|
+
msg = f"A/E calibration completed in {time.time() - start:.2f} seconds"
|
|
143
|
+
log.info(msg)
|
|
37
144
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
145
|
+
out_dict = get_results_dict(aoe)
|
|
146
|
+
aoe_plot_dict = fill_plot_dict(aoe, data, config.get("plot_options", None))
|
|
147
|
+
|
|
148
|
+
aoe.pdf = aoe.pdf.name
|
|
149
|
+
# need to change eres func as can't pickle lambdas
|
|
150
|
+
try:
|
|
151
|
+
aoe.eres_func = results_dicts[next(iter(results_dicts))]["partition_ecal"][
|
|
152
|
+
config["cal_energy_param"]
|
|
153
|
+
]["eres_linear"]
|
|
154
|
+
except KeyError:
|
|
155
|
+
aoe.eres_func = {}
|
|
45
156
|
else:
|
|
46
|
-
|
|
47
|
-
|
|
157
|
+
out_dict = dict.fromkeys(cal_dicts)
|
|
158
|
+
aoe_plot_dict = {}
|
|
159
|
+
aoe = None
|
|
160
|
+
|
|
161
|
+
out_result_dicts = {}
|
|
162
|
+
for tstamp, result_dict in results_dicts.items():
|
|
163
|
+
out_result_dicts[tstamp] = dict(**result_dict, aoe=out_dict[tstamp])
|
|
164
|
+
|
|
165
|
+
out_object_dicts = {}
|
|
166
|
+
for tstamp, object_dict in object_dicts.items():
|
|
167
|
+
out_object_dicts[tstamp] = dict(**object_dict, aoe=aoe)
|
|
168
|
+
|
|
169
|
+
common_dict = (
|
|
170
|
+
aoe_plot_dict.pop("common") if "common" in list(aoe_plot_dict) else None
|
|
171
|
+
)
|
|
172
|
+
out_plot_dicts = {}
|
|
173
|
+
for tstamp, plot_dict in plot_dicts.items():
|
|
174
|
+
if "common" in list(plot_dict) and common_dict is not None:
|
|
175
|
+
plot_dict["common"].update(common_dict)
|
|
176
|
+
elif common_dict is not None:
|
|
177
|
+
plot_dict["common"] = common_dict
|
|
178
|
+
plot_dict.update({"aoe": aoe_plot_dict})
|
|
179
|
+
out_plot_dicts[tstamp] = plot_dict
|
|
180
|
+
|
|
181
|
+
return cal_dicts, out_result_dicts, out_object_dicts, out_plot_dicts
|
|
48
182
|
|
|
49
183
|
|
|
50
184
|
def par_geds_hit_aoe() -> None:
|
|
@@ -79,7 +213,7 @@ def par_geds_hit_aoe() -> None:
|
|
|
79
213
|
configs = TextDB(args.configs, lazy=True).on(args.timestamp, system=args.datatype)
|
|
80
214
|
config_dict = configs["snakemake_rules"]["pars_hit_aoecal"]
|
|
81
215
|
|
|
82
|
-
|
|
216
|
+
build_log(config_dict, args.log)
|
|
83
217
|
|
|
84
218
|
channel_dict = config_dict["inputs"]["aoecal_config"][args.channel]
|
|
85
219
|
kwarg_dict = Props.read_from(channel_dict)
|
|
@@ -91,40 +225,16 @@ def par_geds_hit_aoe() -> None:
|
|
|
91
225
|
with Path(args.eres_file).open("rb") as o:
|
|
92
226
|
object_dict = pkl.load(o)
|
|
93
227
|
|
|
94
|
-
if
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
sigma_func = (
|
|
100
|
-
eval(kwarg_dict.pop("sigma_func"))
|
|
101
|
-
if "sigma_func" in kwarg_dict
|
|
102
|
-
else SigmaFit
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
mean_func = (
|
|
106
|
-
eval(kwarg_dict.pop("mean_func")) if "mean_func" in kwarg_dict else Pol1
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
if "plot_options" in kwarg_dict:
|
|
110
|
-
for field, item in kwarg_dict["plot_options"].items():
|
|
111
|
-
kwarg_dict["plot_options"][field]["function"] = eval(item["function"])
|
|
112
|
-
|
|
113
|
-
with Path(args.files[0]).open() as f:
|
|
114
|
-
files = f.read().splitlines()
|
|
115
|
-
files = sorted(files)
|
|
116
|
-
|
|
117
|
-
try:
|
|
118
|
-
eres = eres_dict[kwarg_dict["cal_energy_param"]]["eres_linear"].copy()
|
|
119
|
-
|
|
120
|
-
def eres_func(x):
|
|
121
|
-
return eval(eres["expression"], dict(x=x, **eres["parameters"]))
|
|
122
|
-
|
|
123
|
-
except KeyError:
|
|
228
|
+
if args.inplots:
|
|
229
|
+
with Path(args.inplots).open("rb") as r:
|
|
230
|
+
out_plot_dict = pkl.load(r)
|
|
231
|
+
else:
|
|
232
|
+
out_plot_dict = {}
|
|
124
233
|
|
|
125
|
-
|
|
126
|
-
|
|
234
|
+
with Path(args.files[0]).open() as f:
|
|
235
|
+
files = sorted(f.read().splitlines())
|
|
127
236
|
|
|
237
|
+
if kwarg_dict["run_aoe"] is True:
|
|
128
238
|
params = [
|
|
129
239
|
kwarg_dict["current_param"],
|
|
130
240
|
"tp_0_est",
|
|
@@ -150,9 +260,11 @@ def par_geds_hit_aoe() -> None:
|
|
|
150
260
|
args.table_name,
|
|
151
261
|
cal_dict,
|
|
152
262
|
params=params,
|
|
153
|
-
threshold=kwarg_dict
|
|
263
|
+
threshold=kwarg_dict["threshold"],
|
|
154
264
|
return_selection_mask=True,
|
|
155
265
|
)
|
|
266
|
+
msg = f"Loaded {len(data)} events"
|
|
267
|
+
log.info(msg)
|
|
156
268
|
|
|
157
269
|
mask = get_pulser_mask(
|
|
158
270
|
pulser_file=args.pulser_file,
|
|
@@ -160,61 +272,35 @@ def par_geds_hit_aoe() -> None:
|
|
|
160
272
|
|
|
161
273
|
data["is_pulser"] = mask[threshold_mask]
|
|
162
274
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
)
|
|
166
|
-
aoe = CalAoE(
|
|
167
|
-
cal_dicts=cal_dict,
|
|
168
|
-
cal_energy_param=kwarg_dict["cal_energy_param"],
|
|
169
|
-
eres_func=eres_func,
|
|
170
|
-
pdf=pdf,
|
|
171
|
-
mean_func=mean_func,
|
|
172
|
-
sigma_func=sigma_func,
|
|
173
|
-
selection_string=f"{kwarg_dict.pop('cut_field')}&(~is_pulser)",
|
|
174
|
-
dt_corr=kwarg_dict.get("dt_corr", False),
|
|
175
|
-
dep_correct=kwarg_dict.get("dep_correct", False),
|
|
176
|
-
dt_cut=kwarg_dict.get("dt_cut", None),
|
|
177
|
-
dt_param=kwarg_dict.get("dt_param", 3),
|
|
178
|
-
high_cut_val=kwarg_dict.get("high_cut_val", 3),
|
|
179
|
-
compt_bands_width=kwarg_dict.get("debug_mode", 20),
|
|
180
|
-
debug_mode=args.debug | kwarg_dict.get("debug_mode", False),
|
|
181
|
-
)
|
|
182
|
-
aoe.update_cal_dicts(
|
|
183
|
-
{
|
|
184
|
-
"AoE_Uncorr": {
|
|
185
|
-
"expression": f"{kwarg_dict['current_param']}/{kwarg_dict['energy_param']}",
|
|
186
|
-
"parameters": {},
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
)
|
|
190
|
-
aoe.calibrate(data, "AoE_Uncorr")
|
|
275
|
+
msg = f"{len(data.query('~is_pulser'))} non pulser events"
|
|
276
|
+
log.info(msg)
|
|
191
277
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
278
|
+
with Path(args.files[0]).open() as f:
|
|
279
|
+
files = f.read().splitlines()
|
|
280
|
+
files = sorted(files)
|
|
195
281
|
|
|
196
|
-
|
|
282
|
+
data["run_timestamp"] = args.timestamp
|
|
197
283
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
284
|
+
cal_dict, results_dicts, object_dicts, plot_dicts = run_aoe_calibration(
|
|
285
|
+
data,
|
|
286
|
+
{args.timestamp: cal_dict},
|
|
287
|
+
{args.timestamp: eres_dict},
|
|
288
|
+
{args.timestamp: object_dict},
|
|
289
|
+
{args.timestamp: out_plot_dict},
|
|
290
|
+
kwarg_dict,
|
|
291
|
+
debug_mode=args.debug,
|
|
292
|
+
)
|
|
293
|
+
cal_dict = cal_dict[args.timestamp]
|
|
294
|
+
results_dict = results_dicts[args.timestamp]
|
|
295
|
+
aoe = object_dicts[args.timestamp]
|
|
296
|
+
plot_dict = plot_dicts[args.timestamp]
|
|
205
297
|
else:
|
|
206
|
-
out_dict = {}
|
|
207
|
-
plot_dict = {}
|
|
208
298
|
aoe = None
|
|
299
|
+
plot_dict = out_plot_dict
|
|
209
300
|
|
|
210
301
|
if args.plot_file:
|
|
211
302
|
common_dict = plot_dict.pop("common") if "common" in list(plot_dict) else None
|
|
212
|
-
|
|
213
|
-
with Path(args.inplots).open("rb") as r:
|
|
214
|
-
out_plot_dict = pkl.load(r)
|
|
215
|
-
out_plot_dict.update({"aoe": plot_dict})
|
|
216
|
-
else:
|
|
217
|
-
out_plot_dict = {"aoe": plot_dict}
|
|
303
|
+
out_plot_dict.update({"aoe": plot_dict})
|
|
218
304
|
|
|
219
305
|
if "common" in list(out_plot_dict) and common_dict is not None:
|
|
220
306
|
out_plot_dict["common"].update(common_dict)
|
|
@@ -226,10 +312,9 @@ def par_geds_hit_aoe() -> None:
|
|
|
226
312
|
pkl.dump(out_plot_dict, w, protocol=pkl.HIGHEST_PROTOCOL)
|
|
227
313
|
|
|
228
314
|
Path(args.hit_pars).parent.mkdir(parents=True, exist_ok=True)
|
|
229
|
-
results_dict = dict(**ecal_dict["results"], aoe=out_dict)
|
|
230
315
|
final_hit_dict = {
|
|
231
316
|
"pars": {"operations": cal_dict},
|
|
232
|
-
"results": results_dict,
|
|
317
|
+
"results": dict(**ecal_dict["results"], aoe=results_dict),
|
|
233
318
|
}
|
|
234
319
|
|
|
235
320
|
final_hit_dict = convert_dict_np_to_float(final_hit_dict)
|
|
@@ -237,9 +322,5 @@ def par_geds_hit_aoe() -> None:
|
|
|
237
322
|
Props.write_to(args.hit_pars, final_hit_dict)
|
|
238
323
|
|
|
239
324
|
Path(args.aoe_results).parent.mkdir(parents=True, exist_ok=True)
|
|
240
|
-
final_object_dict = dict(
|
|
241
|
-
**object_dict,
|
|
242
|
-
aoe=aoe,
|
|
243
|
-
)
|
|
244
325
|
with Path(args.aoe_results).open("wb") as w:
|
|
245
|
-
pkl.dump(
|
|
326
|
+
pkl.dump(dict(**object_dict, aoe=aoe), w, protocol=pkl.HIGHEST_PROTOCOL)
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
+
import copy
|
|
5
|
+
import logging
|
|
4
6
|
import pickle as pkl
|
|
7
|
+
import time
|
|
5
8
|
import warnings
|
|
6
9
|
from pathlib import Path
|
|
7
10
|
|
|
8
11
|
import numpy as np
|
|
12
|
+
import pandas as pd
|
|
9
13
|
from dbetto import TextDB
|
|
10
14
|
from dbetto.catalog import Props
|
|
11
15
|
from pygama.math.distributions import gaussian
|
|
@@ -17,9 +21,11 @@ from pygama.pargen.utils import load_data
|
|
|
17
21
|
from ....utils import (
|
|
18
22
|
build_log,
|
|
19
23
|
convert_dict_np_to_float,
|
|
24
|
+
fill_plot_dict,
|
|
20
25
|
get_pulser_mask,
|
|
21
26
|
)
|
|
22
27
|
|
|
28
|
+
log = logging.getLogger(__name__)
|
|
23
29
|
warnings.filterwarnings(action="ignore", category=RuntimeWarning)
|
|
24
30
|
|
|
25
31
|
|
|
@@ -34,16 +40,172 @@ def get_results_dict(lq_class):
|
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
def lq_calibration(
|
|
44
|
+
data: pd.DataFrame,
|
|
45
|
+
cal_dicts: dict,
|
|
46
|
+
energy_param: str,
|
|
47
|
+
cal_energy_param: str,
|
|
48
|
+
dt_param: str,
|
|
49
|
+
eres_func: callable,
|
|
50
|
+
cdf: callable = gaussian,
|
|
51
|
+
selection_string: str = "",
|
|
52
|
+
plot_options: dict | None = None,
|
|
53
|
+
debug_mode: bool = False,
|
|
54
|
+
):
|
|
55
|
+
"""Loads in data from the provided files and runs the LQ calibration on said files
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
data: pd.DataFrame
|
|
60
|
+
A dataframe containing the data used for calibrating LQ
|
|
61
|
+
cal_dicts: dict
|
|
62
|
+
A dict of hit-level operations to apply to the data
|
|
63
|
+
energy_param: string
|
|
64
|
+
The energy parameter of choice. Used for normalizing the
|
|
65
|
+
raw lq values
|
|
66
|
+
cal_energy_param: string
|
|
67
|
+
The calibrated energy parameter of choice
|
|
68
|
+
dt_param: string
|
|
69
|
+
The drift-time parameter of choice
|
|
70
|
+
eres_func: callable
|
|
71
|
+
The energy resolution functions
|
|
72
|
+
cdf: callable
|
|
73
|
+
The CDF used for the binned fitting of LQ distributions
|
|
74
|
+
cut_field: string
|
|
75
|
+
A string of flags to apply to the data when running the calibration
|
|
76
|
+
plot_options: dict
|
|
77
|
+
A dict containing the plot functions the user wants to run,and any
|
|
78
|
+
user options to provide those plot functions
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
cal_dicts: dict
|
|
82
|
+
The user provided dict, updated with hit-level operations for LQ
|
|
83
|
+
results_dict: dict
|
|
84
|
+
A dict containing the results of the LQ calibration
|
|
85
|
+
plot_dict: dict
|
|
86
|
+
A dict containing all the figures specified by the plot options
|
|
87
|
+
lq: cal_lq class
|
|
88
|
+
The cal_lq object used for the LQ calibration
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
lq = LQCal(
|
|
92
|
+
cal_dicts,
|
|
93
|
+
cal_energy_param,
|
|
94
|
+
dt_param,
|
|
95
|
+
eres_func,
|
|
96
|
+
cdf,
|
|
97
|
+
selection_string,
|
|
98
|
+
debug_mode=debug_mode,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
data["LQ_Ecorr"] = np.divide(data["lq80"], data[energy_param])
|
|
102
|
+
|
|
103
|
+
lq.update_cal_dicts(
|
|
104
|
+
{
|
|
105
|
+
"LQ_Ecorr": {
|
|
106
|
+
"expression": f"lq80/{energy_param}",
|
|
107
|
+
"parameters": {},
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
lq.calibrate(data, "LQ_Ecorr")
|
|
113
|
+
return cal_dicts, get_results_dict(lq), fill_plot_dict(lq, data, plot_options), lq
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def run_lq_calibration(
|
|
117
|
+
data,
|
|
118
|
+
cal_dicts,
|
|
119
|
+
results_dicts,
|
|
120
|
+
object_dicts,
|
|
121
|
+
plot_dicts,
|
|
122
|
+
configs,
|
|
123
|
+
debug_mode=False,
|
|
124
|
+
# gen_plots=True,
|
|
125
|
+
):
|
|
126
|
+
if isinstance(configs, str | list):
|
|
127
|
+
configs = Props.read_from(configs)
|
|
128
|
+
|
|
129
|
+
if configs.pop("run_lq") is True:
|
|
130
|
+
if "plot_options" in configs:
|
|
131
|
+
for field, item in configs["plot_options"].items():
|
|
132
|
+
configs["plot_options"][field]["function"] = eval(item["function"])
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
eres = copy.deepcopy(
|
|
136
|
+
results_dicts[next(iter(results_dicts))]["partition_ecal"][
|
|
137
|
+
configs["cal_energy_param"]
|
|
138
|
+
]["eres_linear"]
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
def eres_func(x):
|
|
142
|
+
return eval(eres["expression"], dict(x=x, **eres["parameters"]))
|
|
143
|
+
|
|
144
|
+
if np.isnan(eres_func(2000)):
|
|
145
|
+
raise RuntimeError
|
|
146
|
+
except (KeyError, RuntimeError):
|
|
147
|
+
try:
|
|
148
|
+
eres = copy.deepcopy(
|
|
149
|
+
results_dicts[next(iter(results_dicts))]["ecal"][
|
|
150
|
+
configs["cal_energy_param"]
|
|
151
|
+
]["eres_linear"]
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
def eres_func(x):
|
|
155
|
+
return eval(eres["expression"], dict(x=x, **eres["parameters"]))
|
|
156
|
+
|
|
157
|
+
except KeyError:
|
|
158
|
+
|
|
159
|
+
def eres_func(x):
|
|
160
|
+
return x * np.nan
|
|
161
|
+
|
|
162
|
+
log.info("starting lq calibration")
|
|
163
|
+
start = time.time()
|
|
164
|
+
cal_dicts, out_dict, lq_plot_dict, lq_obj = lq_calibration(
|
|
165
|
+
data,
|
|
166
|
+
cal_dicts=cal_dicts,
|
|
167
|
+
energy_param=configs["energy_param"],
|
|
168
|
+
cal_energy_param=configs["cal_energy_param"],
|
|
169
|
+
dt_param=configs["dt_param"],
|
|
170
|
+
eres_func=eres_func,
|
|
171
|
+
cdf=eval(configs.get("cdf", "gaussian")),
|
|
172
|
+
selection_string=f"{configs.pop('cut_field')}&(~is_pulser)",
|
|
173
|
+
plot_options=configs.get("plot_options", None),
|
|
174
|
+
debug_mode=debug_mode | configs.get("debug_mode", False),
|
|
175
|
+
)
|
|
176
|
+
msg = f"lq calibration took {time.time() - start:.2f} seconds"
|
|
177
|
+
log.info(msg)
|
|
178
|
+
# need to change eres func as can't pickle lambdas
|
|
179
|
+
try:
|
|
180
|
+
lq_obj.eres_func = results_dicts[next(iter(results_dicts))][
|
|
181
|
+
"partition_ecal"
|
|
182
|
+
][configs["cal_energy_param"]]["eres_linear"]
|
|
183
|
+
except KeyError:
|
|
184
|
+
lq_obj.eres_func = {}
|
|
44
185
|
else:
|
|
45
|
-
|
|
46
|
-
|
|
186
|
+
out_dict = dict.fromkeys(cal_dicts)
|
|
187
|
+
lq_plot_dict = {}
|
|
188
|
+
lq_obj = None
|
|
189
|
+
|
|
190
|
+
out_result_dicts = {}
|
|
191
|
+
for tstamp, result_dict in results_dicts.items():
|
|
192
|
+
out_result_dicts[tstamp] = dict(**result_dict, lq=out_dict)
|
|
193
|
+
|
|
194
|
+
out_object_dicts = {}
|
|
195
|
+
for tstamp, object_dict in object_dicts.items():
|
|
196
|
+
out_object_dicts[tstamp] = dict(**object_dict, lq=lq_obj)
|
|
197
|
+
|
|
198
|
+
common_dict = lq_plot_dict.pop("common") if "common" in list(lq_plot_dict) else None
|
|
199
|
+
out_plot_dicts = {}
|
|
200
|
+
for tstamp, plot_dict in plot_dicts.items():
|
|
201
|
+
if "common" in list(plot_dict) and common_dict is not None:
|
|
202
|
+
plot_dict["common"].update(common_dict)
|
|
203
|
+
elif common_dict is not None:
|
|
204
|
+
plot_dict["common"] = common_dict
|
|
205
|
+
plot_dict.update({"lq": lq_plot_dict})
|
|
206
|
+
out_plot_dicts[tstamp] = plot_dict
|
|
207
|
+
|
|
208
|
+
return cal_dicts, out_result_dicts, out_object_dicts, out_plot_dicts
|
|
47
209
|
|
|
48
210
|
|
|
49
211
|
def par_geds_hit_lq() -> None:
|
|
@@ -78,7 +240,7 @@ def par_geds_hit_lq() -> None:
|
|
|
78
240
|
configs = TextDB(args.configs, lazy=True).on(args.timestamp, system=args.datatype)
|
|
79
241
|
config_dict = configs["snakemake_rules"]["pars_hit_lqcal"]
|
|
80
242
|
|
|
81
|
-
|
|
243
|
+
build_log(config_dict, args.log)
|
|
82
244
|
|
|
83
245
|
channel_dict = config_dict["inputs"]["lqcal_config"][args.channel]
|
|
84
246
|
kwarg_dict = Props.read_from(channel_dict)
|
|
@@ -87,33 +249,20 @@ def par_geds_hit_lq() -> None:
|
|
|
87
249
|
cal_dict = ecal_dict["pars"]["operations"]
|
|
88
250
|
eres_dict = ecal_dict["results"]["ecal"]
|
|
89
251
|
|
|
252
|
+
if args.inplots:
|
|
253
|
+
with Path(args.inplots).open("rb") as r:
|
|
254
|
+
plot_dict = pkl.load(r)
|
|
255
|
+
else:
|
|
256
|
+
plot_dict = {}
|
|
257
|
+
|
|
90
258
|
with Path(args.eres_file).open("rb") as o:
|
|
91
259
|
object_dict = pkl.load(o)
|
|
92
260
|
|
|
93
261
|
if kwarg_dict["run_lq"] is True:
|
|
94
|
-
kwarg_dict.pop("run_lq")
|
|
95
|
-
|
|
96
|
-
cdf = eval(kwarg_dict.pop("cdf")) if "cdf" in kwarg_dict else gaussian
|
|
97
|
-
|
|
98
|
-
if "plot_options" in kwarg_dict:
|
|
99
|
-
for field, item in kwarg_dict["plot_options"].items():
|
|
100
|
-
kwarg_dict["plot_options"][field]["function"] = eval(item["function"])
|
|
101
|
-
|
|
102
262
|
with Path(args.files[0]).open() as f:
|
|
103
263
|
files = f.read().splitlines()
|
|
104
264
|
files = sorted(files)
|
|
105
265
|
|
|
106
|
-
try:
|
|
107
|
-
eres = eres_dict[kwarg_dict["cal_energy_param"]]["eres_linear"].copy()
|
|
108
|
-
|
|
109
|
-
def eres_func(x):
|
|
110
|
-
return eval(eres["expression"], dict(x=x, **eres["parameters"]))
|
|
111
|
-
|
|
112
|
-
except KeyError:
|
|
113
|
-
|
|
114
|
-
def eres_func(x):
|
|
115
|
-
return x * np.nan
|
|
116
|
-
|
|
117
266
|
params = [
|
|
118
267
|
"lq80",
|
|
119
268
|
"dt_eff",
|
|
@@ -132,73 +281,46 @@ def par_geds_hit_lq() -> None:
|
|
|
132
281
|
return_selection_mask=True,
|
|
133
282
|
)
|
|
134
283
|
|
|
284
|
+
msg = f"Loaded {len(data)} events"
|
|
285
|
+
log.info(msg)
|
|
286
|
+
|
|
135
287
|
mask = get_pulser_mask(
|
|
136
288
|
pulser_file=args.pulser_file,
|
|
137
289
|
)
|
|
138
290
|
|
|
139
291
|
data["is_pulser"] = mask[threshold_mask]
|
|
140
292
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
kwarg_dict["cal_energy_param"],
|
|
144
|
-
kwarg_dict["dt_param"],
|
|
145
|
-
eres_func,
|
|
146
|
-
cdf,
|
|
147
|
-
selection_string=f"{kwarg_dict.pop('cut_field')}&(~is_pulser)",
|
|
148
|
-
debug_mode=args.debug | kwarg_dict.get("debug_mode", False),
|
|
149
|
-
)
|
|
293
|
+
msg = f"{len(data.query('~is_pulser'))} non pulser events"
|
|
294
|
+
log.info(msg)
|
|
150
295
|
|
|
151
|
-
data["
|
|
296
|
+
data["run_timestamp"] = args.timestamp
|
|
152
297
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
298
|
+
out_dicts, eres_dicts, plot_dicts, lq_dict = run_lq_calibration(
|
|
299
|
+
data,
|
|
300
|
+
cal_dicts={args.timestamp: cal_dict},
|
|
301
|
+
results_dicts={args.timestamp: eres_dict},
|
|
302
|
+
object_dicts={args.timestamp: object_dict},
|
|
303
|
+
plot_dicts={args.timestamp: plot_dict},
|
|
304
|
+
configs=kwarg_dict,
|
|
305
|
+
debug_mode=args.debug,
|
|
160
306
|
)
|
|
307
|
+
cal_dict = out_dicts[args.timestamp]
|
|
308
|
+
eres_dict = eres_dicts[args.timestamp]
|
|
309
|
+
plot_dict = plot_dicts[args.timestamp]
|
|
310
|
+
lq = lq_dict[args.timestamp]
|
|
161
311
|
|
|
162
|
-
lq.calibrate(data, "LQ_Ecorr")
|
|
163
|
-
log.info("Calibrated LQ")
|
|
164
|
-
|
|
165
|
-
out_dict = get_results_dict(lq)
|
|
166
|
-
plot_dict = fill_plot_dict(lq, data, kwarg_dict.get("plot_options", None))
|
|
167
|
-
|
|
168
|
-
# need to change eres func as can't pickle lambdas
|
|
169
|
-
try:
|
|
170
|
-
lq.eres_func = eres_dict[kwarg_dict["cal_energy_param"]][
|
|
171
|
-
"eres_linear"
|
|
172
|
-
].copy()
|
|
173
|
-
except KeyError:
|
|
174
|
-
lq.eres_func = {}
|
|
175
312
|
else:
|
|
176
|
-
out_dict = {}
|
|
177
|
-
plot_dict = {}
|
|
178
313
|
lq = None
|
|
179
314
|
|
|
180
315
|
if args.plot_file:
|
|
181
|
-
common_dict = plot_dict.pop("common") if "common" in list(plot_dict) else None
|
|
182
|
-
if args.inplots:
|
|
183
|
-
with Path(args.inplots).open("rb") as r:
|
|
184
|
-
out_plot_dict = pkl.load(r)
|
|
185
|
-
out_plot_dict.update({"lq": plot_dict})
|
|
186
|
-
else:
|
|
187
|
-
out_plot_dict = {"lq": plot_dict}
|
|
188
|
-
|
|
189
|
-
if "common" in list(out_plot_dict) and common_dict is not None:
|
|
190
|
-
out_plot_dict["common"].update(common_dict)
|
|
191
|
-
elif common_dict is not None:
|
|
192
|
-
out_plot_dict["common"] = common_dict
|
|
193
|
-
|
|
194
316
|
Path(args.plot_file).parent.mkdir(parents=True, exist_ok=True)
|
|
195
317
|
with Path(args.plot_file).open("wb") as w:
|
|
196
|
-
pkl.dump(
|
|
318
|
+
pkl.dump(plot_dict, w, protocol=pkl.HIGHEST_PROTOCOL)
|
|
197
319
|
|
|
198
320
|
final_hit_dict = convert_dict_np_to_float(
|
|
199
321
|
{
|
|
200
322
|
"pars": {"operations": cal_dict},
|
|
201
|
-
"results": dict(**ecal_dict["results"], lq=
|
|
323
|
+
"results": dict(**ecal_dict["results"], lq=eres_dict),
|
|
202
324
|
}
|
|
203
325
|
)
|
|
204
326
|
Path(args.hit_pars).parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -2,8 +2,10 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
import json
|
|
5
|
+
import logging
|
|
5
6
|
import pickle as pkl
|
|
6
7
|
import re
|
|
8
|
+
import time
|
|
7
9
|
import warnings
|
|
8
10
|
from pathlib import Path
|
|
9
11
|
|
|
@@ -23,83 +25,23 @@ from ....utils import (
|
|
|
23
25
|
get_pulser_mask,
|
|
24
26
|
)
|
|
25
27
|
|
|
28
|
+
log = logging.getLogger(__name__)
|
|
26
29
|
warnings.filterwarnings(action="ignore", category=RuntimeWarning)
|
|
27
30
|
|
|
28
31
|
|
|
29
|
-
def
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
)
|
|
40
|
-
argparser.add_argument(
|
|
41
|
-
"--overwrite-files",
|
|
42
|
-
help="overwrite_files",
|
|
43
|
-
type=str,
|
|
44
|
-
required=False,
|
|
45
|
-
nargs="*",
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
argparser.add_argument("--configs", help="config", type=str, required=True)
|
|
49
|
-
argparser.add_argument("--log", help="log_file", type=str)
|
|
50
|
-
|
|
51
|
-
argparser.add_argument("--datatype", help="Datatype", type=str, required=True)
|
|
52
|
-
argparser.add_argument("--timestamp", help="Timestamp", type=str, required=True)
|
|
53
|
-
argparser.add_argument("--channel", help="Channel", type=str, required=True)
|
|
54
|
-
argparser.add_argument("--table-name", help="table name", type=str, required=True)
|
|
55
|
-
argparser.add_argument("--tier", help="tier", type=str, default="hit")
|
|
56
|
-
|
|
57
|
-
argparser.add_argument("--plot-path", help="plot_path", type=str, required=False)
|
|
58
|
-
argparser.add_argument("--save-path", help="save_path", type=str)
|
|
59
|
-
args = argparser.parse_args()
|
|
60
|
-
|
|
61
|
-
configs = TextDB(args.configs, lazy=True).on(args.timestamp, system=args.datatype)
|
|
62
|
-
if args.tier == "hit":
|
|
63
|
-
config_dict = configs["snakemake_rules"]["pars_hit_qc"]
|
|
64
|
-
elif args.tier == "pht":
|
|
65
|
-
config_dict = configs["snakemake_rules"]["pars_pht_qc"]
|
|
66
|
-
else:
|
|
67
|
-
msg = f"tier {args.tier} not recognized"
|
|
68
|
-
raise ValueError(msg)
|
|
69
|
-
|
|
70
|
-
log = build_log(config_dict, args.log)
|
|
32
|
+
def build_qc(
|
|
33
|
+
config,
|
|
34
|
+
cal_files,
|
|
35
|
+
fft_files,
|
|
36
|
+
table_name,
|
|
37
|
+
overwrite=None,
|
|
38
|
+
pulser_file=None,
|
|
39
|
+
build_plots=False,
|
|
40
|
+
):
|
|
41
|
+
search_name = table_name if table_name[-1] == "/" else table_name + "/"
|
|
71
42
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
kwarg_dict = Props.read_from(channel_dict)
|
|
75
|
-
|
|
76
|
-
if args.overwrite_files:
|
|
77
|
-
overwrite = Props.read_from(args.overwrite_files)
|
|
78
|
-
if args.channel in overwrite:
|
|
79
|
-
overwrite = overwrite[args.channel]["pars"]["operations"]
|
|
80
|
-
else:
|
|
81
|
-
overwrite = None
|
|
82
|
-
else:
|
|
83
|
-
overwrite = None
|
|
84
|
-
|
|
85
|
-
if len(args.fft_files) == 1 and Path(args.fft_files[0]).suffix == ".filelist":
|
|
86
|
-
with Path(args.fft_files[0]).open() as f:
|
|
87
|
-
fft_files = f.read().splitlines()
|
|
88
|
-
else:
|
|
89
|
-
fft_files = args.fft_files
|
|
90
|
-
|
|
91
|
-
if len(args.cal_files) == 1 and Path(args.cal_files[0]).suffix == ".filelist":
|
|
92
|
-
with Path(args.cal_files[0]).open() as f:
|
|
93
|
-
cal_files = f.read().splitlines()
|
|
94
|
-
else:
|
|
95
|
-
cal_files = args.fft_files
|
|
96
|
-
|
|
97
|
-
search_name = (
|
|
98
|
-
args.table_name if args.table_name[-1] == "/" else args.table_name + "/"
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
kwarg_dict_fft = kwarg_dict["fft_fields"]
|
|
102
|
-
kwarg_dict_cal = kwarg_dict["cal_fields"]
|
|
43
|
+
kwarg_dict_fft = config["fft_fields"]
|
|
44
|
+
kwarg_dict_cal = config["cal_fields"]
|
|
103
45
|
|
|
104
46
|
cut_fields = get_keys(
|
|
105
47
|
[key.replace(search_name, "") for key in ls(cal_files[0], search_name)],
|
|
@@ -110,8 +52,8 @@ def par_geds_hit_qc() -> None:
|
|
|
110
52
|
kwarg_dict_fft["cut_parameters"],
|
|
111
53
|
)
|
|
112
54
|
|
|
113
|
-
if "initial_cal_cuts" in
|
|
114
|
-
init_cal =
|
|
55
|
+
if "initial_cal_cuts" in config:
|
|
56
|
+
init_cal = config["initial_cal_cuts"]
|
|
115
57
|
cut_fields += get_keys(
|
|
116
58
|
[key.replace(search_name, "") for key in ls(cal_files[0], search_name)],
|
|
117
59
|
init_cal["cut_parameters"],
|
|
@@ -120,11 +62,14 @@ def par_geds_hit_qc() -> None:
|
|
|
120
62
|
if len(fft_files) > 0:
|
|
121
63
|
fft_data = load_data(
|
|
122
64
|
fft_files,
|
|
123
|
-
|
|
65
|
+
table_name,
|
|
124
66
|
{},
|
|
125
67
|
[*cut_fields, "t_sat_lo", "timestamp", "trapTmax"],
|
|
126
68
|
)
|
|
127
69
|
|
|
70
|
+
msg = f"{len(fft_data)} events"
|
|
71
|
+
log.info(msg)
|
|
72
|
+
|
|
128
73
|
discharges = fft_data["t_sat_lo"] > 0
|
|
129
74
|
discharge_timestamps = np.where(fft_data["timestamp"][discharges])[0]
|
|
130
75
|
is_recovering = np.full(len(fft_data), False, dtype=bool)
|
|
@@ -139,17 +84,22 @@ def par_geds_hit_qc() -> None:
|
|
|
139
84
|
)
|
|
140
85
|
fft_data["is_recovering"] = is_recovering
|
|
141
86
|
|
|
87
|
+
msg = f"{len(fft_data.query('is_recovering'))} discharge recovery events"
|
|
88
|
+
log.info(msg)
|
|
89
|
+
|
|
142
90
|
hit_dict_fft = {}
|
|
143
91
|
plot_dict_fft = {}
|
|
144
92
|
cut_data = fft_data.query("is_recovering==0")
|
|
93
|
+
|
|
145
94
|
msg = f"cut_data shape: {len(cut_data)}"
|
|
146
95
|
log.debug(msg)
|
|
96
|
+
|
|
147
97
|
for name, cut in kwarg_dict_fft["cut_parameters"].items():
|
|
148
98
|
cut_dict, cut_plots = generate_cut_classifiers(
|
|
149
99
|
cut_data,
|
|
150
100
|
{name: cut},
|
|
151
|
-
|
|
152
|
-
display=
|
|
101
|
+
config.get("rounding", 4),
|
|
102
|
+
display=build_plots,
|
|
153
103
|
)
|
|
154
104
|
hit_dict_fft.update(cut_dict)
|
|
155
105
|
plot_dict_fft.update(cut_plots)
|
|
@@ -189,7 +139,7 @@ def par_geds_hit_qc() -> None:
|
|
|
189
139
|
# load data in
|
|
190
140
|
data, threshold_mask = load_data(
|
|
191
141
|
cal_files,
|
|
192
|
-
|
|
142
|
+
table_name,
|
|
193
143
|
{},
|
|
194
144
|
[*cut_fields, "timestamp", "trapTmax", "t_sat_lo"],
|
|
195
145
|
threshold=kwarg_dict_cal.get("threshold", 0),
|
|
@@ -198,11 +148,14 @@ def par_geds_hit_qc() -> None:
|
|
|
198
148
|
)
|
|
199
149
|
|
|
200
150
|
mask = get_pulser_mask(
|
|
201
|
-
pulser_file=
|
|
151
|
+
pulser_file=pulser_file,
|
|
202
152
|
)
|
|
203
153
|
|
|
204
154
|
data["is_pulser"] = mask[threshold_mask]
|
|
205
155
|
|
|
156
|
+
msg = f"{len(data.query('~is_pulser'))} non pulser events"
|
|
157
|
+
log.info(msg)
|
|
158
|
+
|
|
206
159
|
discharges = data["t_sat_lo"] > 0
|
|
207
160
|
discharge_timestamps = np.where(data["timestamp"][discharges])[0]
|
|
208
161
|
is_recovering = np.full(len(data), False, dtype=bool)
|
|
@@ -217,19 +170,22 @@ def par_geds_hit_qc() -> None:
|
|
|
217
170
|
)
|
|
218
171
|
data["is_recovering"] = is_recovering
|
|
219
172
|
|
|
173
|
+
msg = f"{len(data.query('is_recovering'))} discharge recovery events"
|
|
174
|
+
log.info(msg)
|
|
175
|
+
|
|
220
176
|
rng = np.random.default_rng()
|
|
221
177
|
mask = np.full(len(data.query("~is_pulser & ~is_recovering")), False, dtype=bool)
|
|
222
178
|
mask[
|
|
223
179
|
rng.choice(len(data.query("~is_pulser & ~is_recovering")), 4000, replace=False)
|
|
224
180
|
] = True
|
|
225
181
|
|
|
226
|
-
if "initial_cal_cuts" in
|
|
227
|
-
init_cal =
|
|
182
|
+
if "initial_cal_cuts" in config:
|
|
183
|
+
init_cal = config["initial_cal_cuts"]
|
|
228
184
|
hit_dict_init_cal, plot_dict_init_cal = generate_cut_classifiers(
|
|
229
185
|
data.query("~is_pulser & ~is_recovering")[mask],
|
|
230
186
|
init_cal["cut_parameters"],
|
|
231
187
|
init_cal.get("rounding", 4),
|
|
232
|
-
display=
|
|
188
|
+
display=build_plots,
|
|
233
189
|
)
|
|
234
190
|
ct_mask = np.full(len(data), True, dtype=bool)
|
|
235
191
|
for outname, info in hit_dict_init_cal.items():
|
|
@@ -260,8 +216,8 @@ def par_geds_hit_qc() -> None:
|
|
|
260
216
|
hit_dict_cal, plot_dict_cal = generate_cut_classifiers(
|
|
261
217
|
cal_data,
|
|
262
218
|
kwarg_dict_cal["cut_parameters"],
|
|
263
|
-
|
|
264
|
-
display=
|
|
219
|
+
config.get("rounding", 4),
|
|
220
|
+
display=build_plots,
|
|
265
221
|
)
|
|
266
222
|
|
|
267
223
|
if overwrite is not None:
|
|
@@ -273,8 +229,6 @@ def par_geds_hit_qc() -> None:
|
|
|
273
229
|
hit_dict = {**hit_dict_fft, **hit_dict_init_cal, **hit_dict_cal}
|
|
274
230
|
plot_dict = {**plot_dict_fft, **plot_dict_init_cal, **plot_dict_cal}
|
|
275
231
|
|
|
276
|
-
hit_dict = convert_dict_np_to_float(hit_dict)
|
|
277
|
-
|
|
278
232
|
for outname, info in hit_dict.items():
|
|
279
233
|
# convert to pandas eval
|
|
280
234
|
exp = info["expression"]
|
|
@@ -305,6 +259,7 @@ def par_geds_hit_qc() -> None:
|
|
|
305
259
|
)
|
|
306
260
|
sf_cal *= 100
|
|
307
261
|
sf_fft *= 100
|
|
262
|
+
|
|
308
263
|
msg = f"{entry} cut applied: {sf_cal:.2f}% of events passed the cut for cal data, {sf_fft:.2f}% for fft data"
|
|
309
264
|
log.info(msg)
|
|
310
265
|
qc_results[entry] = {
|
|
@@ -313,12 +268,93 @@ def par_geds_hit_qc() -> None:
|
|
|
313
268
|
"sf_fft": sf_fft,
|
|
314
269
|
"sf_fft_err": sf_fft_err,
|
|
315
270
|
}
|
|
316
|
-
qc_results = convert_dict_np_to_float(qc_results)
|
|
317
271
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
272
|
+
out_dict = convert_dict_np_to_float(
|
|
273
|
+
{"operations": hit_dict, "results": {"qc": qc_results}}
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
return out_dict, plot_dict
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def par_geds_hit_qc() -> None:
|
|
280
|
+
argparser = argparse.ArgumentParser()
|
|
281
|
+
argparser.add_argument("--cal-files", help="cal_files", nargs="*", type=str)
|
|
282
|
+
argparser.add_argument("--fft-files", help="fft_files", nargs="*", type=str)
|
|
283
|
+
|
|
284
|
+
argparser.add_argument(
|
|
285
|
+
"--tcm-filelist", help="tcm_filelist", type=str, required=False
|
|
286
|
+
)
|
|
287
|
+
argparser.add_argument(
|
|
288
|
+
"--pulser-file", help="pulser_file", type=str, required=False
|
|
289
|
+
)
|
|
290
|
+
argparser.add_argument(
|
|
291
|
+
"--overwrite-files",
|
|
292
|
+
help="overwrite_files",
|
|
293
|
+
type=str,
|
|
294
|
+
required=False,
|
|
295
|
+
nargs="*",
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
argparser.add_argument("--configs", help="config", type=str, required=True)
|
|
299
|
+
argparser.add_argument("--log", help="log_file", type=str)
|
|
300
|
+
|
|
301
|
+
argparser.add_argument("--datatype", help="Datatype", type=str, required=True)
|
|
302
|
+
argparser.add_argument("--timestamp", help="Timestamp", type=str, required=True)
|
|
303
|
+
argparser.add_argument("--channel", help="Channel", type=str, required=True)
|
|
304
|
+
argparser.add_argument("--table-name", help="table name", type=str, required=True)
|
|
305
|
+
argparser.add_argument("--tier", help="tier", type=str, default="hit")
|
|
306
|
+
|
|
307
|
+
argparser.add_argument("--plot-path", help="plot_path", type=str, required=False)
|
|
308
|
+
argparser.add_argument("--save-path", help="save_path", type=str)
|
|
309
|
+
args = argparser.parse_args()
|
|
310
|
+
|
|
311
|
+
configs = TextDB(args.configs, lazy=True).on(args.timestamp, system=args.datatype)
|
|
312
|
+
config_dict = configs["snakemake_rules"]["pars_hit_qc"]
|
|
313
|
+
|
|
314
|
+
build_log(config_dict, args.log)
|
|
315
|
+
|
|
316
|
+
# get metadata dictionary
|
|
317
|
+
channel_dict = config_dict["inputs"]["qc_config"][args.channel]
|
|
318
|
+
kwarg_dict = Props.read_from(channel_dict)
|
|
319
|
+
|
|
320
|
+
if args.overwrite_files:
|
|
321
|
+
overwrite = Props.read_from(args.overwrite_files)
|
|
322
|
+
if args.channel in overwrite:
|
|
323
|
+
overwrite = overwrite[args.channel]["pars"]["operations"]
|
|
324
|
+
else:
|
|
325
|
+
overwrite = None
|
|
326
|
+
else:
|
|
327
|
+
overwrite = None
|
|
328
|
+
|
|
329
|
+
if len(args.fft_files) == 1 and Path(args.fft_files[0]).suffix == ".filelist":
|
|
330
|
+
with Path(args.fft_files[0]).open() as f:
|
|
331
|
+
fft_files = f.read().splitlines()
|
|
332
|
+
else:
|
|
333
|
+
fft_files = args.fft_files
|
|
334
|
+
|
|
335
|
+
if len(args.cal_files) == 1 and Path(args.cal_files[0]).suffix == ".filelist":
|
|
336
|
+
with Path(args.cal_files[0]).open() as f:
|
|
337
|
+
cal_files = f.read().splitlines()
|
|
338
|
+
else:
|
|
339
|
+
cal_files = args.fft_files
|
|
340
|
+
|
|
341
|
+
start = time.time()
|
|
342
|
+
log.info("starting qc")
|
|
343
|
+
|
|
344
|
+
out_dict, plot_dict = build_qc(
|
|
345
|
+
config=kwarg_dict,
|
|
346
|
+
cal_files=cal_files,
|
|
347
|
+
fft_files=fft_files,
|
|
348
|
+
table_name=args.table_name,
|
|
349
|
+
overwrite=overwrite,
|
|
350
|
+
pulser_file=args.pulser_file,
|
|
351
|
+
build_plots=int(bool(args.plot_path)),
|
|
321
352
|
)
|
|
353
|
+
msg = f"qc took {time.time() - start:.2f} seconds"
|
|
354
|
+
log.info(msg)
|
|
355
|
+
|
|
356
|
+
Path(args.save_path).parent.mkdir(parents=True, exist_ok=True)
|
|
357
|
+
Props.write_to(args.save_path, out_dict)
|
|
322
358
|
|
|
323
359
|
if args.plot_path:
|
|
324
360
|
Path(args.plot_path).parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -4,12 +4,14 @@ from .alias_table import alias_table
|
|
|
4
4
|
from .cfgtools import get_channel_config
|
|
5
5
|
from .convert_np import convert_dict_np_to_float
|
|
6
6
|
from .log import build_log
|
|
7
|
+
from .plot_dict import fill_plot_dict
|
|
7
8
|
from .pulser_removal import get_pulser_mask
|
|
8
9
|
|
|
9
10
|
__all__ = [
|
|
10
11
|
"alias_table",
|
|
11
12
|
"build_log",
|
|
12
13
|
"convert_dict_np_to_float",
|
|
14
|
+
"fill_plot_dict",
|
|
13
15
|
"get_channel_config",
|
|
14
16
|
"get_pulser_mask",
|
|
15
17
|
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def fill_plot_dict(plot_class, data, plot_options, plot_dict=None):
|
|
5
|
+
if plot_dict is None:
|
|
6
|
+
plot_dict = {}
|
|
7
|
+
else:
|
|
8
|
+
for key, item in plot_options.items():
|
|
9
|
+
if item["options"] is not None:
|
|
10
|
+
plot_dict[key] = item["function"](plot_class, data, **item["options"])
|
|
11
|
+
else:
|
|
12
|
+
plot_dict[key] = item["function"](plot_class, data)
|
|
13
|
+
return plot_dict
|
{legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.3.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.3.dist-info}/top_level.txt
RENAMED
|
File without changes
|