legend-dataflow-scripts 0.1.2__py3-none-any.whl → 0.1.4__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.4.dist-info}/METADATA +2 -2
- {legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.4.dist-info}/RECORD +13 -12
- {legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.4.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 +149 -102
- legenddataflowscripts/utils/__init__.py +2 -0
- legenddataflowscripts/utils/plot_dict.py +13 -0
- legenddataflowscripts/workflow/__init__.py +2 -0
- {legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.4.dist-info}/entry_points.txt +0 -0
- {legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.4.dist-info}/top_level.txt +0 -0
{legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.4.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.4
|
|
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=hcPkC9vIGgfrKK6ft7ysLT7iOCjpFmCBmyKLmXiaZ1g,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=16RWhybvnODv4dUuSkO6EDtPvJJJmeFwFaPTgS9N7cs,12746
|
|
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
|
-
legenddataflowscripts/workflow/__init__.py,sha256=
|
|
28
|
+
legenddataflowscripts/workflow/__init__.py,sha256=JhudKYhBT8bXtX4LCqxQCHzUiITpugAtFxePWEtphC4,474
|
|
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.4.dist-info/METADATA,sha256=kCV4uTOiqJBCGvMteN0O5b0YGwLCMrZR8DF3LytqCF4,3122
|
|
34
|
+
legend_dataflow_scripts-0.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
35
|
+
legend_dataflow_scripts-0.1.4.dist-info/entry_points.txt,sha256=B197waSm-orA_ZS-9rkxNDsmOHdCn8CbWodnlqXQKRg,1313
|
|
36
|
+
legend_dataflow_scripts-0.1.4.dist-info/top_level.txt,sha256=s8E2chjJNYUbrN6whFG_VCsJKySFp1IOXLcUefA7DB0,22
|
|
37
|
+
legend_dataflow_scripts-0.1.4.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)
|
|
71
|
-
|
|
72
|
-
# get metadata dictionary
|
|
73
|
-
channel_dict = config_dict["inputs"]["qc_config"][args.channel]
|
|
74
|
-
kwarg_dict = Props.read_from(channel_dict)
|
|
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 + "/"
|
|
75
42
|
|
|
76
|
-
|
|
77
|
-
|
|
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)
|
|
@@ -179,6 +129,7 @@ def par_geds_hit_qc() -> None:
|
|
|
179
129
|
else:
|
|
180
130
|
hit_dict_fft = {}
|
|
181
131
|
plot_dict_fft = {}
|
|
132
|
+
fft_data = None
|
|
182
133
|
|
|
183
134
|
if overwrite is not None:
|
|
184
135
|
for name in kwarg_dict_fft["cut_parameters"]:
|
|
@@ -189,7 +140,7 @@ def par_geds_hit_qc() -> None:
|
|
|
189
140
|
# load data in
|
|
190
141
|
data, threshold_mask = load_data(
|
|
191
142
|
cal_files,
|
|
192
|
-
|
|
143
|
+
table_name,
|
|
193
144
|
{},
|
|
194
145
|
[*cut_fields, "timestamp", "trapTmax", "t_sat_lo"],
|
|
195
146
|
threshold=kwarg_dict_cal.get("threshold", 0),
|
|
@@ -198,11 +149,14 @@ def par_geds_hit_qc() -> None:
|
|
|
198
149
|
)
|
|
199
150
|
|
|
200
151
|
mask = get_pulser_mask(
|
|
201
|
-
pulser_file=
|
|
152
|
+
pulser_file=pulser_file,
|
|
202
153
|
)
|
|
203
154
|
|
|
204
155
|
data["is_pulser"] = mask[threshold_mask]
|
|
205
156
|
|
|
157
|
+
msg = f"{len(data.query('~is_pulser'))} non pulser events"
|
|
158
|
+
log.info(msg)
|
|
159
|
+
|
|
206
160
|
discharges = data["t_sat_lo"] > 0
|
|
207
161
|
discharge_timestamps = np.where(data["timestamp"][discharges])[0]
|
|
208
162
|
is_recovering = np.full(len(data), False, dtype=bool)
|
|
@@ -217,19 +171,22 @@ def par_geds_hit_qc() -> None:
|
|
|
217
171
|
)
|
|
218
172
|
data["is_recovering"] = is_recovering
|
|
219
173
|
|
|
174
|
+
msg = f"{len(data.query('is_recovering'))} discharge recovery events"
|
|
175
|
+
log.info(msg)
|
|
176
|
+
|
|
220
177
|
rng = np.random.default_rng()
|
|
221
178
|
mask = np.full(len(data.query("~is_pulser & ~is_recovering")), False, dtype=bool)
|
|
222
179
|
mask[
|
|
223
180
|
rng.choice(len(data.query("~is_pulser & ~is_recovering")), 4000, replace=False)
|
|
224
181
|
] = True
|
|
225
182
|
|
|
226
|
-
if "initial_cal_cuts" in
|
|
227
|
-
init_cal =
|
|
183
|
+
if "initial_cal_cuts" in config:
|
|
184
|
+
init_cal = config["initial_cal_cuts"]
|
|
228
185
|
hit_dict_init_cal, plot_dict_init_cal = generate_cut_classifiers(
|
|
229
186
|
data.query("~is_pulser & ~is_recovering")[mask],
|
|
230
187
|
init_cal["cut_parameters"],
|
|
231
188
|
init_cal.get("rounding", 4),
|
|
232
|
-
display=
|
|
189
|
+
display=build_plots,
|
|
233
190
|
)
|
|
234
191
|
ct_mask = np.full(len(data), True, dtype=bool)
|
|
235
192
|
for outname, info in hit_dict_init_cal.items():
|
|
@@ -260,8 +217,8 @@ def par_geds_hit_qc() -> None:
|
|
|
260
217
|
hit_dict_cal, plot_dict_cal = generate_cut_classifiers(
|
|
261
218
|
cal_data,
|
|
262
219
|
kwarg_dict_cal["cut_parameters"],
|
|
263
|
-
|
|
264
|
-
display=
|
|
220
|
+
config.get("rounding", 4),
|
|
221
|
+
display=build_plots,
|
|
265
222
|
)
|
|
266
223
|
|
|
267
224
|
if overwrite is not None:
|
|
@@ -273,14 +230,12 @@ def par_geds_hit_qc() -> None:
|
|
|
273
230
|
hit_dict = {**hit_dict_fft, **hit_dict_init_cal, **hit_dict_cal}
|
|
274
231
|
plot_dict = {**plot_dict_fft, **plot_dict_init_cal, **plot_dict_cal}
|
|
275
232
|
|
|
276
|
-
hit_dict = convert_dict_np_to_float(hit_dict)
|
|
277
|
-
|
|
278
233
|
for outname, info in hit_dict.items():
|
|
279
234
|
# convert to pandas eval
|
|
280
235
|
exp = info["expression"]
|
|
281
236
|
for key in info.get("parameters", None):
|
|
282
237
|
exp = re.sub(f"(?<![a-zA-Z0-9]){key}(?![a-zA-Z0-9])", f"@{key}", exp)
|
|
283
|
-
if outname not in fft_data:
|
|
238
|
+
if fft_data is not None and outname not in fft_data:
|
|
284
239
|
fft_data[outname] = fft_data.eval(
|
|
285
240
|
exp, local_dict=info.get("parameters", None)
|
|
286
241
|
)
|
|
@@ -297,28 +252,120 @@ def par_geds_hit_qc() -> None:
|
|
|
297
252
|
((sf_cal) * (1 - sf_cal))
|
|
298
253
|
/ len(data.query("~is_pulser & ~is_recovering"))
|
|
299
254
|
)
|
|
300
|
-
sf_fft = len(fft_data.query(f"{entry} & ~is_recovering")) / len(
|
|
301
|
-
fft_data.query("~is_recovering")
|
|
302
|
-
)
|
|
303
|
-
sf_fft_err = 100 * np.sqrt(
|
|
304
|
-
((sf_fft) * (1 - sf_fft)) / len(fft_data.query("~is_recovering"))
|
|
305
|
-
)
|
|
306
255
|
sf_cal *= 100
|
|
307
|
-
|
|
308
|
-
msg = f"{entry} cut applied: {sf_cal:.2f}% of events passed the cut for cal data, {sf_fft:.2f}% for fft data"
|
|
256
|
+
msg = f"{entry} cut applied: {sf_cal:.2f}% of events passed the cut for cal data"
|
|
309
257
|
log.info(msg)
|
|
258
|
+
|
|
310
259
|
qc_results[entry] = {
|
|
311
260
|
"sf_cal": sf_cal,
|
|
312
261
|
"sf_cal_err": sf_cal_err,
|
|
313
|
-
"sf_fft": sf_fft,
|
|
314
|
-
"sf_fft_err": sf_fft_err,
|
|
315
262
|
}
|
|
316
|
-
qc_results = convert_dict_np_to_float(qc_results)
|
|
317
263
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
264
|
+
if fft_data is not None:
|
|
265
|
+
sf_fft = len(fft_data.query(f"{entry} & ~is_recovering")) / len(
|
|
266
|
+
fft_data.query("~is_recovering")
|
|
267
|
+
)
|
|
268
|
+
sf_fft_err = 100 * np.sqrt(
|
|
269
|
+
((sf_fft) * (1 - sf_fft)) / len(fft_data.query("~is_recovering"))
|
|
270
|
+
)
|
|
271
|
+
sf_fft *= 100
|
|
272
|
+
msg = f"{entry} cut applied: {sf_fft:.2f}% of events passed the cut for fft data"
|
|
273
|
+
|
|
274
|
+
log.info(msg)
|
|
275
|
+
|
|
276
|
+
qc_results[entry].update(
|
|
277
|
+
{
|
|
278
|
+
"sf_fft": sf_fft,
|
|
279
|
+
"sf_fft_err": sf_fft_err,
|
|
280
|
+
}
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
out_dict = convert_dict_np_to_float(
|
|
284
|
+
{"operations": hit_dict, "results": {"qc": qc_results}}
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
return out_dict, plot_dict
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def par_geds_hit_qc() -> None:
|
|
291
|
+
argparser = argparse.ArgumentParser()
|
|
292
|
+
argparser.add_argument("--cal-files", help="cal_files", nargs="*", type=str)
|
|
293
|
+
argparser.add_argument("--fft-files", help="fft_files", nargs="*", type=str)
|
|
294
|
+
|
|
295
|
+
argparser.add_argument(
|
|
296
|
+
"--tcm-filelist", help="tcm_filelist", type=str, required=False
|
|
297
|
+
)
|
|
298
|
+
argparser.add_argument(
|
|
299
|
+
"--pulser-file", help="pulser_file", type=str, required=False
|
|
300
|
+
)
|
|
301
|
+
argparser.add_argument(
|
|
302
|
+
"--overwrite-files",
|
|
303
|
+
help="overwrite_files",
|
|
304
|
+
type=str,
|
|
305
|
+
required=False,
|
|
306
|
+
nargs="*",
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
argparser.add_argument("--configs", help="config", type=str, required=True)
|
|
310
|
+
argparser.add_argument("--log", help="log_file", type=str)
|
|
311
|
+
|
|
312
|
+
argparser.add_argument("--datatype", help="Datatype", type=str, required=True)
|
|
313
|
+
argparser.add_argument("--timestamp", help="Timestamp", type=str, required=True)
|
|
314
|
+
argparser.add_argument("--channel", help="Channel", type=str, required=True)
|
|
315
|
+
argparser.add_argument("--table-name", help="table name", type=str, required=True)
|
|
316
|
+
argparser.add_argument("--tier", help="tier", type=str, default="hit")
|
|
317
|
+
|
|
318
|
+
argparser.add_argument("--plot-path", help="plot_path", type=str, required=False)
|
|
319
|
+
argparser.add_argument("--save-path", help="save_path", type=str)
|
|
320
|
+
args = argparser.parse_args()
|
|
321
|
+
|
|
322
|
+
configs = TextDB(args.configs, lazy=True).on(args.timestamp, system=args.datatype)
|
|
323
|
+
config_dict = configs["snakemake_rules"]["pars_hit_qc"]
|
|
324
|
+
|
|
325
|
+
build_log(config_dict, args.log)
|
|
326
|
+
|
|
327
|
+
# get metadata dictionary
|
|
328
|
+
channel_dict = config_dict["inputs"]["qc_config"][args.channel]
|
|
329
|
+
kwarg_dict = Props.read_from(channel_dict)
|
|
330
|
+
|
|
331
|
+
if args.overwrite_files:
|
|
332
|
+
overwrite = Props.read_from(args.overwrite_files)
|
|
333
|
+
if args.channel in overwrite:
|
|
334
|
+
overwrite = overwrite[args.channel]["pars"]["operations"]
|
|
335
|
+
else:
|
|
336
|
+
overwrite = None
|
|
337
|
+
else:
|
|
338
|
+
overwrite = None
|
|
339
|
+
|
|
340
|
+
if len(args.fft_files) == 1 and Path(args.fft_files[0]).suffix == ".filelist":
|
|
341
|
+
with Path(args.fft_files[0]).open() as f:
|
|
342
|
+
fft_files = f.read().splitlines()
|
|
343
|
+
else:
|
|
344
|
+
fft_files = args.fft_files
|
|
345
|
+
|
|
346
|
+
if len(args.cal_files) == 1 and Path(args.cal_files[0]).suffix == ".filelist":
|
|
347
|
+
with Path(args.cal_files[0]).open() as f:
|
|
348
|
+
cal_files = f.read().splitlines()
|
|
349
|
+
else:
|
|
350
|
+
cal_files = args.fft_files
|
|
351
|
+
|
|
352
|
+
start = time.time()
|
|
353
|
+
log.info("starting qc")
|
|
354
|
+
|
|
355
|
+
out_dict, plot_dict = build_qc(
|
|
356
|
+
config=kwarg_dict,
|
|
357
|
+
cal_files=cal_files,
|
|
358
|
+
fft_files=fft_files,
|
|
359
|
+
table_name=args.table_name,
|
|
360
|
+
overwrite=overwrite,
|
|
361
|
+
pulser_file=args.pulser_file,
|
|
362
|
+
build_plots=int(bool(args.plot_path)),
|
|
321
363
|
)
|
|
364
|
+
msg = f"qc took {time.time() - start:.2f} seconds"
|
|
365
|
+
log.info(msg)
|
|
366
|
+
|
|
367
|
+
Path(args.save_path).parent.mkdir(parents=True, exist_ok=True)
|
|
368
|
+
Props.write_to(args.save_path, out_dict)
|
|
322
369
|
|
|
323
370
|
if args.plot_path:
|
|
324
371
|
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
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from .execenv import execenv_prefix, execenv_pyexe
|
|
4
|
+
from .pre_compile_catalog import pre_compile_catalog
|
|
4
5
|
from .utils import (
|
|
5
6
|
as_ro,
|
|
6
7
|
set_last_rule_name,
|
|
@@ -13,6 +14,7 @@ __all__ = [
|
|
|
13
14
|
"as_ro",
|
|
14
15
|
"execenv_prefix",
|
|
15
16
|
"execenv_pyexe",
|
|
17
|
+
"pre_compile_catalog",
|
|
16
18
|
"set_last_rule_name",
|
|
17
19
|
"subst_vars",
|
|
18
20
|
"subst_vars_impl",
|
{legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.4.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{legend_dataflow_scripts-0.1.2.dist-info → legend_dataflow_scripts-0.1.4.dist-info}/top_level.txt
RENAMED
|
File without changes
|