pygama 2.3.8a2__tar.gz → 2.3.8a3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pygama-2.3.8a2/src/pygama.egg-info → pygama-2.3.8a3}/PKG-INFO +1 -1
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/_version.py +3 -3
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/evt/build_evt.py +6 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/hit/build_hit.py +3 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/pargen/AoE_cal.py +330 -111
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/pargen/dplms_ge_dict.py +11 -42
- {pygama-2.3.8a2 → pygama-2.3.8a3/src/pygama.egg-info}/PKG-INFO +1 -1
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/evt/test_build_evt.py +27 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/hit/test_build_hit.py +27 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/LICENSE +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/README.md +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/pyproject.toml +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/setup.cfg +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/__init__.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/cli.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/evt/__init__.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/evt/aggregators.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/evt/build_tcm.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/evt/modules/__init__.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/evt/modules/geds.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/evt/modules/larveto.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/evt/modules/legend.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/evt/modules/spms.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/evt/modules/xtalk.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/evt/tcm.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/evt/utils.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/flow/__init__.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/flow/data_loader.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/flow/file_db.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/flow/utils.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/hit/__init__.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/logging.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/__init__.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/binned_fitting.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/distributions.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/__init__.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/crystal_ball.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/error_function.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/exgauss.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/exponential.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/gauss.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/gauss_on_exgauss.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/gauss_on_exponential.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/gauss_on_linear.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/gauss_on_step.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/gauss_on_uniform.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/hpge_peak.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/linear.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/moyal.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/poisson.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/polynomial.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/pygama_continuous.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/step.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/sum_dists.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/triple_gauss_on_double_step.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/functions/uniform.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/histogram.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/hpge_peak_fitting.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/least_squares.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/unbinned_fitting.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/units.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/math/utils.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/pargen/__init__.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/pargen/data_cleaning.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/pargen/dsp_optimize.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/pargen/energy_cal.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/pargen/energy_optimisation.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/pargen/lq_cal.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/pargen/noise_optimization.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/pargen/pz_correct.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/pargen/survival_fractions.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/pargen/utils.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama/utils.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama.egg-info/SOURCES.txt +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama.egg-info/dependency_links.txt +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama.egg-info/entry_points.txt +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama.egg-info/not-zip-safe +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama.egg-info/requires.txt +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/src/pygama.egg-info/top_level.txt +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/configs/icpc-dsp-config.json +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/configs/sipm-dplms-config.json +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/configs/sipm-dsp-config.json +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/conftest.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/evt/configs/basic-evt-config.yaml +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/evt/configs/query-test-evt-config.json +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/evt/configs/spms-module-config.yaml +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/evt/configs/spms-p13-config.yaml +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/evt/configs/vov-test-evt-config.json +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/evt/modules/larveto.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/evt/test_build_tcm.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/evt/test_evt_utils.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/evt/test_geds.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/evt/test_xtalk.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/flow/configs/config.json +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/flow/configs/data-loader-config.json +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/flow/configs/filedb-config.json +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/flow/configs/nested/config.json +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/flow/configs/nested/data-loader-config-nested.json +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/flow/conftest.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/flow/test_data_loader.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/flow/test_filedb.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/flow/test_flow_utils.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/hit/configs/aggregations-hit-config.json +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/hit/configs/basic-hit-config.json +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/hit/configs/hit-multi-config.json +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_crystal_ball.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_error_function.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_exgauss.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_exponential.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_gauss.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_gauss_on_exgauss.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_gauss_on_exponential.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_gauss_on_linear.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_gauss_on_step.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_gauss_on_uniform.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_hpge_peak.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_linear.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_moyal.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_numba_frozen.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_poisson.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_polynomial.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_step.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_sum_dists.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_triple_gauss_on_double_step.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/functions/test_uniform.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/test_binned_fitting.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/test_distribution_selector_in_sum_dists.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/test_hpge_peak_fitting.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/test_iminuit_integration.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/test_least_squares.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/test_math_histogram.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/test_math_utils.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/math/test_unbinned_fitting.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/pargen/test_aoecal.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/pargen/test_datacleaning.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/pargen/test_dsp_optimize.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/pargen/test_ecal.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/pargen/test_energy_optimization.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/pargen/test_lqcal.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/pargen/test_pz_correct.py +0 -0
- {pygama-2.3.8a2 → pygama-2.3.8a3}/tests/test_utils.py +0 -0
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '2.3.
|
|
22
|
-
__version_tuple__ = version_tuple = (2, 3, 8, '
|
|
21
|
+
__version__ = version = '2.3.8a3'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 3, 8, 'a3')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g5a070cc53'
|
|
@@ -308,6 +308,9 @@ def build_evt_cols(
|
|
|
308
308
|
if "lgdo_attrs" in v:
|
|
309
309
|
obj.attrs |= v["lgdo_attrs"]
|
|
310
310
|
|
|
311
|
+
if "description" in v:
|
|
312
|
+
obj.attrs["description"] = v["description"]
|
|
313
|
+
|
|
311
314
|
# else we build the event entry
|
|
312
315
|
else:
|
|
313
316
|
if "channels" not in v:
|
|
@@ -357,6 +360,9 @@ def build_evt_cols(
|
|
|
357
360
|
if "lgdo_attrs" in v:
|
|
358
361
|
obj.attrs |= v["lgdo_attrs"]
|
|
359
362
|
|
|
363
|
+
if "description" in v:
|
|
364
|
+
obj.attrs["description"] = v["description"]
|
|
365
|
+
|
|
360
366
|
# cast to type, if required
|
|
361
367
|
# hijack the poor LGDO
|
|
362
368
|
if "dtype" in v:
|
|
@@ -156,6 +156,9 @@ def build_hit(
|
|
|
156
156
|
if "lgdo_attrs" in info:
|
|
157
157
|
outcol.attrs |= info["lgdo_attrs"]
|
|
158
158
|
|
|
159
|
+
if "description" in info:
|
|
160
|
+
outcol.attrs["description"] = info["description"]
|
|
161
|
+
|
|
159
162
|
log.debug("made new column %r=%r", outname, outcol)
|
|
160
163
|
outtbl_obj.add_column(outname, outcol)
|
|
161
164
|
|
|
@@ -18,6 +18,7 @@ import pandas as pd
|
|
|
18
18
|
from iminuit import Minuit, cost
|
|
19
19
|
from matplotlib.colors import LogNorm
|
|
20
20
|
from scipy.stats import chi2
|
|
21
|
+
from sklearn.covariance import MinCovDet
|
|
21
22
|
|
|
22
23
|
import pygama.math.binned_fitting as pgf
|
|
23
24
|
import pygama.math.histogram as pgh
|
|
@@ -743,6 +744,290 @@ def interpolate_consecutive(tstamps, means, times, aoe_param, output_name):
|
|
|
743
744
|
return out_dict
|
|
744
745
|
|
|
745
746
|
|
|
747
|
+
def bimodal_dt_fit(
|
|
748
|
+
data: pd.DataFrame,
|
|
749
|
+
aoe_param: str,
|
|
750
|
+
dt_param: str,
|
|
751
|
+
fit_selection: str,
|
|
752
|
+
cal_energy_param: str,
|
|
753
|
+
pdf,
|
|
754
|
+
debug_mode: bool = False,
|
|
755
|
+
display: int = 0,
|
|
756
|
+
**_kwargs,
|
|
757
|
+
) -> tuple[float, dict]:
|
|
758
|
+
"""
|
|
759
|
+
Calculates the correction needed to align the two drift time regions for ICPC detectors.
|
|
760
|
+
This is done by fitting the two drift time peaks in the drift time spectrum and then
|
|
761
|
+
fitting the A/E peaks in each of these regions. A simple linear correction is then applied
|
|
762
|
+
to align these regions.
|
|
763
|
+
|
|
764
|
+
Parameters
|
|
765
|
+
----------
|
|
766
|
+
data
|
|
767
|
+
DataFrame containing the data.
|
|
768
|
+
aoe_param
|
|
769
|
+
Name of the A/E parameter to use as starting point.
|
|
770
|
+
dt_param
|
|
771
|
+
Name of the drift time parameter.
|
|
772
|
+
fit_selection
|
|
773
|
+
Selection string for the fit.
|
|
774
|
+
cal_energy_param
|
|
775
|
+
Name of the calibrated energy parameter.
|
|
776
|
+
pdf
|
|
777
|
+
PDF to use for the A/E fit.
|
|
778
|
+
debug_mode
|
|
779
|
+
If True, re-raises exceptions instead of logging them.
|
|
780
|
+
display
|
|
781
|
+
Plot verbosity level.
|
|
782
|
+
|
|
783
|
+
Returns
|
|
784
|
+
-------
|
|
785
|
+
alpha
|
|
786
|
+
Linear correction coefficient.
|
|
787
|
+
dt_res_dict
|
|
788
|
+
Dictionary containing intermediate fit results.
|
|
789
|
+
"""
|
|
790
|
+
log.info("Starting A/E drift time correction (bimodal_dt_fit mode)")
|
|
791
|
+
dt_res_dict = {}
|
|
792
|
+
alpha = 0
|
|
793
|
+
try:
|
|
794
|
+
dep_events = data.query(
|
|
795
|
+
f"{fit_selection}&{cal_energy_param}>1582&{cal_energy_param}<1602&{cal_energy_param}=={cal_energy_param}&{aoe_param}=={aoe_param}"
|
|
796
|
+
)
|
|
797
|
+
|
|
798
|
+
hist, bins, var = pgh.get_hist(
|
|
799
|
+
dep_events[aoe_param],
|
|
800
|
+
bins=500,
|
|
801
|
+
)
|
|
802
|
+
bin_cs = (bins[1:] + bins[:-1]) / 2
|
|
803
|
+
mu = bin_cs[np.argmax(hist)]
|
|
804
|
+
aoe_range = [mu * 0.9, mu * 1.1]
|
|
805
|
+
|
|
806
|
+
dt_range = [
|
|
807
|
+
np.nanpercentile(dep_events[dt_param], 1),
|
|
808
|
+
np.nanpercentile(dep_events[dt_param], 99),
|
|
809
|
+
]
|
|
810
|
+
|
|
811
|
+
dt_res_dict["final_selection"] = (
|
|
812
|
+
f"{aoe_param}>{aoe_range[0]}&{aoe_param}<{aoe_range[1]}&{dt_param}>{dt_range[0]}&{dt_param}<{dt_range[1]}&{dt_param}=={dt_param}"
|
|
813
|
+
)
|
|
814
|
+
|
|
815
|
+
final_df = dep_events.query(dt_res_dict["final_selection"])
|
|
816
|
+
|
|
817
|
+
hist, bins, var = pgh.get_hist(
|
|
818
|
+
final_df[dt_param],
|
|
819
|
+
dx=32,
|
|
820
|
+
range=(
|
|
821
|
+
np.nanmin(final_df[dt_param]),
|
|
822
|
+
np.nanmax(final_df[dt_param]),
|
|
823
|
+
),
|
|
824
|
+
)
|
|
825
|
+
|
|
826
|
+
bcs = pgh.get_bin_centers(bins)
|
|
827
|
+
mus = bcs[pgc.get_i_local_maxima(hist / (np.sqrt(var) + 10**-99), 2)]
|
|
828
|
+
pk_pars, _pk_covs = pgc.hpge_fit_energy_peak_tops(
|
|
829
|
+
hist,
|
|
830
|
+
bins,
|
|
831
|
+
var=var,
|
|
832
|
+
peak_locs=mus,
|
|
833
|
+
n_to_fit=5,
|
|
834
|
+
)
|
|
835
|
+
|
|
836
|
+
mus = pk_pars[:, 0]
|
|
837
|
+
sigmas = pk_pars[:, 1]
|
|
838
|
+
amps = pk_pars[:, 2]
|
|
839
|
+
|
|
840
|
+
if len(mus) > 2:
|
|
841
|
+
ids = np.array(
|
|
842
|
+
sorted([np.argmax(amps), np.argmax(amps[amps != np.argmax(amps)])])
|
|
843
|
+
)
|
|
844
|
+
else:
|
|
845
|
+
ids = np.full(len(mus), True, dtype=bool)
|
|
846
|
+
mus = mus[ids]
|
|
847
|
+
sigmas = sigmas[ids]
|
|
848
|
+
amps = amps[ids]
|
|
849
|
+
|
|
850
|
+
dt_res_dict["dt_fit"] = {"mus": mus, "sigmas": sigmas, "amps": amps}
|
|
851
|
+
|
|
852
|
+
if len(mus) < 2:
|
|
853
|
+
log.info("Only 1 drift time peak found, no correction needed")
|
|
854
|
+
|
|
855
|
+
else:
|
|
856
|
+
aoe_grp1 = dt_res_dict["aoe_grp1"] = (
|
|
857
|
+
f"{dt_param}>{mus[0] - 2 * sigmas[0]} & {dt_param}<{mus[0] + 2 * sigmas[0]}"
|
|
858
|
+
)
|
|
859
|
+
aoe_grp2 = dt_res_dict["aoe_grp2"] = (
|
|
860
|
+
f"{dt_param}>{mus[1] - 2 * sigmas[1]} & {dt_param}<{mus[1] + 2 * sigmas[1]}"
|
|
861
|
+
)
|
|
862
|
+
|
|
863
|
+
aoe_pars, aoe_errs, _, _ = unbinned_aoe_fit(
|
|
864
|
+
final_df.query(aoe_grp1)[aoe_param], pdf=pdf, display=display
|
|
865
|
+
)
|
|
866
|
+
dt_res_dict["aoe_fit1"] = {
|
|
867
|
+
"pars": aoe_pars.to_dict(),
|
|
868
|
+
"errs": aoe_errs.to_dict(),
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
aoe_pars2, aoe_errs2, _, _ = unbinned_aoe_fit(
|
|
872
|
+
final_df.query(aoe_grp2)[aoe_param], pdf=pdf, display=display
|
|
873
|
+
)
|
|
874
|
+
dt_res_dict["aoe_fit2"] = {
|
|
875
|
+
"pars": aoe_pars2.to_dict(),
|
|
876
|
+
"errs": aoe_errs2.to_dict(),
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
try:
|
|
880
|
+
alpha = (aoe_pars2["mu"] - aoe_pars["mu"]) / (
|
|
881
|
+
(mus[0] * aoe_pars["mu"]) - (mus[1] * aoe_pars2["mu"])
|
|
882
|
+
)
|
|
883
|
+
except ZeroDivisionError:
|
|
884
|
+
alpha = 0
|
|
885
|
+
|
|
886
|
+
dt_res_dict["alpha"] = alpha
|
|
887
|
+
log.info("dtcorr successful alpha: %s", alpha)
|
|
888
|
+
|
|
889
|
+
except BaseException as e:
|
|
890
|
+
if isinstance(e, KeyboardInterrupt) or debug_mode:
|
|
891
|
+
raise e
|
|
892
|
+
log.error("Drift time correction (bimodal_dt_fit) failed")
|
|
893
|
+
|
|
894
|
+
return alpha, dt_res_dict
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
def mcdrift(
|
|
898
|
+
data: pd.DataFrame,
|
|
899
|
+
aoe_param: str,
|
|
900
|
+
dt_param: str,
|
|
901
|
+
fit_selection: str,
|
|
902
|
+
cal_energy_param: str,
|
|
903
|
+
debug_mode: bool = False,
|
|
904
|
+
**_kwargs,
|
|
905
|
+
) -> tuple[float, dict]:
|
|
906
|
+
"""
|
|
907
|
+
Calculates the drift time correction for the A/E parameter using the
|
|
908
|
+
Minimum Covariance Determinant (MCD) method and PCA on the (AoE, dt_eff) distribution.
|
|
909
|
+
|
|
910
|
+
Parameters
|
|
911
|
+
----------
|
|
912
|
+
data
|
|
913
|
+
DataFrame containing the data.
|
|
914
|
+
aoe_param
|
|
915
|
+
Name of the A/E parameter to use as starting point.
|
|
916
|
+
dt_param
|
|
917
|
+
Name of the drift time parameter.
|
|
918
|
+
fit_selection
|
|
919
|
+
Selection string for the fit.
|
|
920
|
+
cal_energy_param
|
|
921
|
+
Name of the calibrated energy parameter.
|
|
922
|
+
debug_mode
|
|
923
|
+
If True, re-raises exceptions instead of logging them.
|
|
924
|
+
|
|
925
|
+
Returns
|
|
926
|
+
-------
|
|
927
|
+
alpha
|
|
928
|
+
Linear correction coefficient.
|
|
929
|
+
dt_res_dict
|
|
930
|
+
Dictionary containing intermediate fit results.
|
|
931
|
+
"""
|
|
932
|
+
log.info("Starting A/E drift time correction (MCD mode)")
|
|
933
|
+
|
|
934
|
+
try:
|
|
935
|
+
CC_events = data.query(
|
|
936
|
+
f"{fit_selection}&{cal_energy_param}=={cal_energy_param}&{aoe_param}=={aoe_param}&{dt_param}=={dt_param}"
|
|
937
|
+
)
|
|
938
|
+
except Exception as e:
|
|
939
|
+
if debug_mode:
|
|
940
|
+
raise e
|
|
941
|
+
log.error("MCD drift: event selection query failed: %s", e)
|
|
942
|
+
return 0, {}
|
|
943
|
+
|
|
944
|
+
peaks = np.array([1080, 1094, 1459, 1512, 1552, 1620, 1650, 1670, 1830, 2105])
|
|
945
|
+
CC_selection = (CC_events[cal_energy_param] >= 1000) & (
|
|
946
|
+
CC_events[cal_energy_param] <= 2400
|
|
947
|
+
)
|
|
948
|
+
for peak in peaks:
|
|
949
|
+
CC_selection &= ~(
|
|
950
|
+
(CC_events[cal_energy_param] >= peak - 5)
|
|
951
|
+
& (CC_events[cal_energy_param] <= peak + 5)
|
|
952
|
+
)
|
|
953
|
+
CC_events = CC_events[CC_selection]
|
|
954
|
+
|
|
955
|
+
if len(CC_events) == 0:
|
|
956
|
+
log.error("MCD drift: no CC events found after selection")
|
|
957
|
+
return 0, {}
|
|
958
|
+
|
|
959
|
+
aoe_vals = CC_events[aoe_param].to_numpy()
|
|
960
|
+
dt_vals = CC_events[dt_param].to_numpy() / 1000.0 # convert to us for stability
|
|
961
|
+
mcd_data = np.column_stack([aoe_vals, dt_vals])
|
|
962
|
+
|
|
963
|
+
# --- find AoE range ---
|
|
964
|
+
classifier = mcd_data[:, 0]
|
|
965
|
+
xrange = (0.9, 1.1)
|
|
966
|
+
bin_width_x = (
|
|
967
|
+
0.5
|
|
968
|
+
* (np.nanpercentile(classifier, 75) - np.nanpercentile(classifier, 25))
|
|
969
|
+
* len(classifier) ** (-1 / 3)
|
|
970
|
+
)
|
|
971
|
+
if bin_width_x <= 0:
|
|
972
|
+
log.error("MCD drift: degenerate AoE distribution, bin width <= 0")
|
|
973
|
+
return 0, {}
|
|
974
|
+
|
|
975
|
+
xbins = int((xrange[1] - xrange[0]) / bin_width_x)
|
|
976
|
+
counts, bin_edges = np.histogram(classifier, bins=xbins, range=xrange, density=True)
|
|
977
|
+
bin_centers = (bin_edges[:-1] + bin_edges[1:]) / 2
|
|
978
|
+
peak_position = bin_centers[np.argmax(counts)]
|
|
979
|
+
half_max = np.max(counts) / 2.0
|
|
980
|
+
indices_above_half = np.where(counts >= half_max)[0]
|
|
981
|
+
|
|
982
|
+
if len(indices_above_half) < 2:
|
|
983
|
+
log.error("MCD drift: could not determine FWHM of AoE peak")
|
|
984
|
+
return 0, {}
|
|
985
|
+
|
|
986
|
+
bw = bin_centers[1] - bin_centers[0]
|
|
987
|
+
fwhm = bin_centers[indices_above_half[-1]] - bin_centers[indices_above_half[0]] + bw
|
|
988
|
+
x_low = peak_position - 2 * fwhm
|
|
989
|
+
x_high = peak_position + 3 * fwhm
|
|
990
|
+
|
|
991
|
+
# --- MCD fit ---
|
|
992
|
+
in_x = (mcd_data[:, 0] >= x_low) & (mcd_data[:, 0] <= x_high)
|
|
993
|
+
in_y = (mcd_data[:, 1] >= 0) & (
|
|
994
|
+
mcd_data[:, 1] <= np.quantile(mcd_data[:, 1], 0.999)
|
|
995
|
+
)
|
|
996
|
+
subset = mcd_data[in_x & in_y]
|
|
997
|
+
|
|
998
|
+
if len(subset) < 2:
|
|
999
|
+
log.error("MCD drift: insufficient events in AoE range for MCD fit")
|
|
1000
|
+
return 0, {}
|
|
1001
|
+
|
|
1002
|
+
try:
|
|
1003
|
+
mcd = MinCovDet().fit(subset)
|
|
1004
|
+
except Exception as e:
|
|
1005
|
+
if debug_mode:
|
|
1006
|
+
raise e
|
|
1007
|
+
log.error("MCD drift: MCD fit failed: %s", e)
|
|
1008
|
+
return 0, {}
|
|
1009
|
+
|
|
1010
|
+
# --- PCA slope ---
|
|
1011
|
+
_, eigvecs = np.linalg.eigh(mcd.covariance_)
|
|
1012
|
+
principal = eigvecs[:, -1]
|
|
1013
|
+
if abs(principal[0]) > abs(principal[1]):
|
|
1014
|
+
log.warning(
|
|
1015
|
+
"Principal eigenvector not aligned with drift time axis (|v_aoe|=%.4f > |v_dt|=%.4f), "
|
|
1016
|
+
"switching to minor eigenvector",
|
|
1017
|
+
abs(principal[0]),
|
|
1018
|
+
abs(principal[1]),
|
|
1019
|
+
)
|
|
1020
|
+
principal = eigvecs[:, -2]
|
|
1021
|
+
|
|
1022
|
+
if abs(principal[1]) < 1e-10:
|
|
1023
|
+
log.error("MCD drift: eigenvector has near-zero dt component")
|
|
1024
|
+
return 0, {}
|
|
1025
|
+
|
|
1026
|
+
alpha = -principal[0] / principal[1] / 1000.0
|
|
1027
|
+
log.info("dtcorr (MCD) successful alpha: %s", alpha)
|
|
1028
|
+
return alpha, {"alpha": alpha}
|
|
1029
|
+
|
|
1030
|
+
|
|
746
1031
|
class CalAoE:
|
|
747
1032
|
"""
|
|
748
1033
|
Class for calibrating the A/E,
|
|
@@ -1149,15 +1434,17 @@ class CalAoE:
|
|
|
1149
1434
|
def drift_time_correction(
|
|
1150
1435
|
self,
|
|
1151
1436
|
data: pd.DataFrame,
|
|
1152
|
-
aoe_param,
|
|
1153
|
-
out_param="AoE_DTcorr",
|
|
1437
|
+
aoe_param: str = "AoE_Timecorr",
|
|
1438
|
+
out_param: str = "AoE_DTcorr",
|
|
1439
|
+
mode: str = "mcdrift",
|
|
1154
1440
|
display: int = 0,
|
|
1155
1441
|
):
|
|
1156
1442
|
"""
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
to
|
|
1443
|
+
Apply a linear drift-time correction to the A/E distribution.
|
|
1444
|
+
|
|
1445
|
+
Estimates a linear correction coefficient to align the A/E values
|
|
1446
|
+
across drift time and writes the corrected parameter to the DataFrame
|
|
1447
|
+
and calibration dictionary.
|
|
1161
1448
|
|
|
1162
1449
|
Parameters
|
|
1163
1450
|
----------
|
|
@@ -1165,119 +1452,46 @@ class CalAoE:
|
|
|
1165
1452
|
data
|
|
1166
1453
|
DataFrame containing the data.
|
|
1167
1454
|
aoe_param
|
|
1168
|
-
Name of the A/E parameter to use as starting point.
|
|
1455
|
+
Name of the A/E parameter to use as the starting point for correction.
|
|
1169
1456
|
out_param
|
|
1170
|
-
Name of the output parameter for the drift-time-corrected A/E
|
|
1171
|
-
|
|
1457
|
+
Name of the output parameter for the drift-time-corrected A/E,
|
|
1458
|
+
stored in the DataFrame and added to the calibration dictionary.
|
|
1459
|
+
mode
|
|
1460
|
+
Mode used to estimate the correction coefficient. Options:
|
|
1461
|
+
- ``"mcdrift"`` : Minimum Covariance Determinant (MCD) based estimation
|
|
1462
|
+
(improved stability for low statistic and no evident structure)
|
|
1463
|
+
- ``"bimodal_dt_fit"`` : Fit the position of two drift time peaks
|
|
1464
|
+
(heavily relying on DEP events and clear structure).
|
|
1172
1465
|
display
|
|
1173
1466
|
Plot verbosity level.
|
|
1174
1467
|
|
|
1175
1468
|
"""
|
|
1176
1469
|
log.info("Starting A/E drift time correction")
|
|
1177
|
-
self.dt_res_dict = {}
|
|
1178
|
-
try:
|
|
1179
|
-
dep_events = data.query(
|
|
1180
|
-
f"{self.fit_selection}&{self.cal_energy_param}>1582&{self.cal_energy_param}<1602&{self.cal_energy_param}=={self.cal_energy_param}&{aoe_param}=={aoe_param}"
|
|
1181
|
-
)
|
|
1182
1470
|
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
bin_cs = (bins[1:] + bins[:-1]) / 2
|
|
1188
|
-
mu = bin_cs[np.argmax(hist)]
|
|
1189
|
-
aoe_range = [mu * 0.9, mu * 1.1]
|
|
1190
|
-
|
|
1191
|
-
dt_range = [
|
|
1192
|
-
np.nanpercentile(dep_events[self.dt_param], 1),
|
|
1193
|
-
np.nanpercentile(dep_events[self.dt_param], 99),
|
|
1194
|
-
]
|
|
1195
|
-
|
|
1196
|
-
self.dt_res_dict["final_selection"] = (
|
|
1197
|
-
f"{aoe_param}>{aoe_range[0]}&{aoe_param}<{aoe_range[1]}&{self.dt_param}>{dt_range[0]}&{self.dt_param}<{dt_range[1]}&{self.dt_param}=={self.dt_param}"
|
|
1198
|
-
)
|
|
1199
|
-
|
|
1200
|
-
final_df = dep_events.query(self.dt_res_dict["final_selection"])
|
|
1201
|
-
|
|
1202
|
-
hist, bins, var = pgh.get_hist(
|
|
1203
|
-
final_df[self.dt_param],
|
|
1204
|
-
dx=32,
|
|
1205
|
-
range=(
|
|
1206
|
-
np.nanmin(final_df[self.dt_param]),
|
|
1207
|
-
np.nanmax(final_df[self.dt_param]),
|
|
1208
|
-
),
|
|
1209
|
-
)
|
|
1210
|
-
|
|
1211
|
-
bcs = pgh.get_bin_centers(bins)
|
|
1212
|
-
mus = bcs[pgc.get_i_local_maxima(hist / (np.sqrt(var) + 10**-99), 2)]
|
|
1213
|
-
pk_pars, _pk_covs = pgc.hpge_fit_energy_peak_tops(
|
|
1214
|
-
hist,
|
|
1215
|
-
bins,
|
|
1216
|
-
var=var,
|
|
1217
|
-
peak_locs=mus,
|
|
1218
|
-
n_to_fit=5,
|
|
1219
|
-
)
|
|
1220
|
-
|
|
1221
|
-
mus = pk_pars[:, 0]
|
|
1222
|
-
sigmas = pk_pars[:, 1]
|
|
1223
|
-
amps = pk_pars[:, 2]
|
|
1224
|
-
|
|
1225
|
-
if len(mus) > 2:
|
|
1226
|
-
ids = np.array(
|
|
1227
|
-
sorted([np.argmax(amps), np.argmax(amps[amps != np.argmax(amps)])])
|
|
1228
|
-
)
|
|
1229
|
-
else:
|
|
1230
|
-
ids = np.full(len(mus), True, dtype=bool)
|
|
1231
|
-
mus = mus[ids]
|
|
1232
|
-
sigmas = sigmas[ids]
|
|
1233
|
-
amps = amps[ids]
|
|
1234
|
-
|
|
1235
|
-
self.dt_res_dict["dt_fit"] = {"mus": mus, "sigmas": sigmas, "amps": amps}
|
|
1236
|
-
|
|
1237
|
-
if len(mus) < 2:
|
|
1238
|
-
log.info("Only 1 drift time peak found, no correction needed")
|
|
1239
|
-
self.alpha = 0
|
|
1240
|
-
|
|
1241
|
-
else:
|
|
1242
|
-
aoe_grp1 = self.dt_res_dict["aoe_grp1"] = (
|
|
1243
|
-
f"{self.dt_param}>{mus[0] - 2 * sigmas[0]} & {self.dt_param}<{mus[0] + 2 * sigmas[0]}"
|
|
1244
|
-
)
|
|
1245
|
-
aoe_grp2 = self.dt_res_dict["aoe_grp2"] = (
|
|
1246
|
-
f"{self.dt_param}>{mus[1] - 2 * sigmas[1]} & {self.dt_param}<{mus[1] + 2 * sigmas[1]}"
|
|
1247
|
-
)
|
|
1248
|
-
|
|
1249
|
-
aoe_pars, aoe_errs, _, _ = unbinned_aoe_fit(
|
|
1250
|
-
final_df.query(aoe_grp1)[aoe_param], pdf=self.pdf, display=display
|
|
1251
|
-
)
|
|
1252
|
-
|
|
1253
|
-
self.dt_res_dict["aoe_fit1"] = {
|
|
1254
|
-
"pars": aoe_pars.to_dict(),
|
|
1255
|
-
"errs": aoe_errs.to_dict(),
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
aoe_pars2, aoe_errs2, _, _ = unbinned_aoe_fit(
|
|
1259
|
-
final_df.query(aoe_grp2)[aoe_param], pdf=self.pdf, display=display
|
|
1260
|
-
)
|
|
1261
|
-
|
|
1262
|
-
self.dt_res_dict["aoe_fit2"] = {
|
|
1263
|
-
"pars": aoe_pars2.to_dict(),
|
|
1264
|
-
"errs": aoe_errs2.to_dict(),
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
try:
|
|
1268
|
-
self.alpha = (aoe_pars2["mu"] - aoe_pars["mu"]) / (
|
|
1269
|
-
(mus[0] * aoe_pars["mu"]) - (mus[1] * aoe_pars2["mu"])
|
|
1270
|
-
)
|
|
1271
|
-
except ZeroDivisionError:
|
|
1272
|
-
self.alpha = 0
|
|
1273
|
-
self.dt_res_dict["alpha"] = self.alpha
|
|
1274
|
-
log.info("dtcorr successful alpha:%s", self.alpha)
|
|
1471
|
+
_modes = {
|
|
1472
|
+
"mcdrift": mcdrift,
|
|
1473
|
+
"bimodal_dt_fit": bimodal_dt_fit,
|
|
1474
|
+
}
|
|
1275
1475
|
|
|
1276
|
-
|
|
1277
|
-
if isinstance(e, KeyboardInterrupt) or self.debug_mode:
|
|
1278
|
-
raise (e)
|
|
1279
|
-
log.error("Drift time correction failed")
|
|
1476
|
+
if mode not in _modes:
|
|
1280
1477
|
self.alpha = 0
|
|
1478
|
+
log.error(
|
|
1479
|
+
"Unknown mode '%s' for drift time correction. Valid options are: %s",
|
|
1480
|
+
mode,
|
|
1481
|
+
list(_modes),
|
|
1482
|
+
)
|
|
1483
|
+
return
|
|
1484
|
+
|
|
1485
|
+
self.alpha, self.dt_res_dict = _modes[mode](
|
|
1486
|
+
data,
|
|
1487
|
+
aoe_param,
|
|
1488
|
+
dt_param=self.dt_param,
|
|
1489
|
+
fit_selection=self.fit_selection,
|
|
1490
|
+
cal_energy_param=self.cal_energy_param,
|
|
1491
|
+
pdf=self.pdf,
|
|
1492
|
+
debug_mode=self.debug_mode,
|
|
1493
|
+
display=display,
|
|
1494
|
+
)
|
|
1281
1495
|
|
|
1282
1496
|
data[out_param] = data[aoe_param] * (1 + self.alpha * data[self.dt_param])
|
|
1283
1497
|
self.update_cal_dicts(
|
|
@@ -1923,6 +2137,7 @@ class CalAoE:
|
|
|
1923
2137
|
sf_nsamples: int = 11,
|
|
1924
2138
|
sf_cut_range: tuple = (-5, 5),
|
|
1925
2139
|
timecorr_mode: str = "full",
|
|
2140
|
+
dtcorr_mode: str = "mcdrift",
|
|
1926
2141
|
override_dict: dict | None = None,
|
|
1927
2142
|
):
|
|
1928
2143
|
"""
|
|
@@ -1950,6 +2165,8 @@ class CalAoE:
|
|
|
1950
2165
|
Range of A/E cut values to use for the survival fraction sweep.
|
|
1951
2166
|
timecorr_mode
|
|
1952
2167
|
Mode to use for the time correction; see :meth:`time_correction` for details.
|
|
2168
|
+
dtcorr_mode
|
|
2169
|
+
Mode to use for the drift time correction; see :meth:`drift_time_correction` for details.
|
|
1953
2170
|
override_dict
|
|
1954
2171
|
Optional dictionary of pre-computed calibration entries that bypass one or more
|
|
1955
2172
|
fit steps. Each key should map to a sub-dict with ``"expression"`` (a string
|
|
@@ -1993,7 +2210,9 @@ class CalAoE:
|
|
|
1993
2210
|
if self.dt_corr is True:
|
|
1994
2211
|
aoe_param = "AoE_DTcorr"
|
|
1995
2212
|
if override_dict is None or "AoE_DTcorr" not in override_dict:
|
|
1996
|
-
self.drift_time_correction(
|
|
2213
|
+
self.drift_time_correction(
|
|
2214
|
+
df, "AoE_Timecorr", out_param=aoe_param, mode=dtcorr_mode
|
|
2215
|
+
)
|
|
1997
2216
|
else:
|
|
1998
2217
|
self.update_cal_dicts({"AoE_DTcorr": override_dict["AoE_DTcorr"]})
|
|
1999
2218
|
df["AoE_DTcorr"] = ne.evaluate(
|
|
@@ -14,7 +14,6 @@ from lgdo import Table
|
|
|
14
14
|
from scipy.signal import convolve, convolve2d
|
|
15
15
|
from scipy.stats import chi2
|
|
16
16
|
|
|
17
|
-
from pygama.pargen.data_cleaning import generate_cuts
|
|
18
17
|
from pygama.pargen.dsp_optimize import run_one_dsp
|
|
19
18
|
from pygama.pargen.energy_optimisation import fom_fwhm_with_alpha_fit
|
|
20
19
|
|
|
@@ -39,7 +38,8 @@ def dplms_ge_dict(
|
|
|
39
38
|
Parameters
|
|
40
39
|
----------
|
|
41
40
|
raw_fft
|
|
42
|
-
|
|
41
|
+
Table with FFT raw data already baseline-selected upstream. All events in
|
|
42
|
+
this table are used to estimate the noise matrix.
|
|
43
43
|
raw_cal
|
|
44
44
|
table with cal raw data
|
|
45
45
|
dsp_config
|
|
@@ -57,33 +57,18 @@ def dplms_ge_dict(
|
|
|
57
57
|
"""
|
|
58
58
|
|
|
59
59
|
t0 = time.time()
|
|
60
|
-
log.info("
|
|
60
|
+
log.info("Using baseline-selected FFT events")
|
|
61
61
|
|
|
62
62
|
dsp_fft = run_one_dsp(raw_fft, dsp_config, db_dict=par_dsp)
|
|
63
63
|
|
|
64
|
-
cut_dict = generate_cuts(dsp_fft, cut_dict=dplms_dict["bls_cut_pars"])
|
|
65
|
-
log.debug("Cuts are %s", cut_dict)
|
|
66
|
-
idxs = np.full(len(dsp_fft), True, dtype=bool)
|
|
67
|
-
for outname, info in cut_dict.items():
|
|
68
|
-
outcol = dsp_fft.eval(info["expression"], info.get("parameters", None))
|
|
69
|
-
dsp_fft.add_column(outname, outcol)
|
|
70
|
-
for cut in cut_dict:
|
|
71
|
-
idxs = dsp_fft[cut].nda & idxs
|
|
72
|
-
log.debug("Applied Cuts")
|
|
73
|
-
|
|
74
64
|
bl_field = dplms_dict["bl_field"]
|
|
75
|
-
log.info("... %s baselines
|
|
65
|
+
log.info("... %s baselines", len(dsp_fft[bl_field].values.nda))
|
|
76
66
|
|
|
77
|
-
bls = dsp_fft[bl_field].values.nda[
|
|
78
|
-
bls_par = {}
|
|
79
|
-
bls_cut_pars = list(dplms_dict["bls_cut_pars"])
|
|
80
|
-
for par in bls_cut_pars:
|
|
81
|
-
bls_par[par] = dsp_fft[dplms_dict["bls_cut_pars"][par]["cut_parameter"]].nda
|
|
67
|
+
bls = dsp_fft[bl_field].values.nda[:, : dplms_dict["bsize"]]
|
|
82
68
|
t1 = time.time()
|
|
83
69
|
log.info(
|
|
84
|
-
"
|
|
70
|
+
"using %s baseline-selected events for noise estimation in %.2f s",
|
|
85
71
|
len(raw_fft),
|
|
86
|
-
len(bls),
|
|
87
72
|
t1 - t0,
|
|
88
73
|
)
|
|
89
74
|
log.info(
|
|
@@ -304,27 +289,7 @@ def dplms_ge_dict(
|
|
|
304
289
|
ax.plot(wf)
|
|
305
290
|
ax.legend(loc="upper right")
|
|
306
291
|
plot_dict["bls"] = fig
|
|
307
|
-
|
|
308
|
-
for ii, par in enumerate(bls_cut_pars):
|
|
309
|
-
if "parameters" in cut_dict[par]:
|
|
310
|
-
if "a" in cut_dict[par]["parameters"]:
|
|
311
|
-
llo = cut_dict[par]["parameters"]["a"]
|
|
312
|
-
else:
|
|
313
|
-
llo = np.nan
|
|
314
|
-
if "b" in cut_dict[par]["parameters"]:
|
|
315
|
-
lup = cut_dict[par]["parameters"]["b"]
|
|
316
|
-
else:
|
|
317
|
-
lup = np.nan
|
|
318
|
-
mean = (lup + llo) / 2
|
|
319
|
-
plo, pup = mean - 2 * (mean - llo), mean + 2 * (lup - mean)
|
|
320
|
-
hh, bb = np.histogram(bls_par[par], bins=np.linspace(plo, pup, 200))
|
|
321
|
-
ax.flat[ii].plot(bb[1:], hh, ds="steps", label=f"cut on {par}")
|
|
322
|
-
ax.flat[ii].axvline(lup, color="k", linestyle=":", label="selection")
|
|
323
|
-
ax.flat[ii].axvline(llo, color="k", linestyle=":")
|
|
324
|
-
ax.flat[ii].set_xlabel(par)
|
|
325
|
-
ax.flat[ii].set_yscale("log")
|
|
326
|
-
ax.flat[ii].legend(loc="upper right")
|
|
327
|
-
plot_dict["bl_sel"] = fig
|
|
292
|
+
plt.close()
|
|
328
293
|
|
|
329
294
|
wf_idxs = np.random.choice(len(wfs), dplms_dict["n_plot"]) # noqa: NPY002
|
|
330
295
|
wfs = wfs[wf_idxs]
|
|
@@ -343,6 +308,7 @@ def dplms_ge_dict(
|
|
|
343
308
|
axin.set_xlim(wsize / 2 - dplms_dict["zoom"], wsize / 2 + dplms_dict["zoom"])
|
|
344
309
|
axin.set_yticklabels("")
|
|
345
310
|
plot_dict["wfs"] = fig
|
|
311
|
+
plt.close()
|
|
346
312
|
|
|
347
313
|
peak_pos = dsp_cal["peak_pos"].nda
|
|
348
314
|
risetime = dsp_cal["tp_90"].nda - dsp_cal["tp_10"].nda
|
|
@@ -392,6 +358,7 @@ def dplms_ge_dict(
|
|
|
392
358
|
ax.flat[0].set_yscale("log")
|
|
393
359
|
ax.flat[0].legend(loc="upper right")
|
|
394
360
|
plot_dict["wf_sel"] = fig
|
|
361
|
+
plt.close()
|
|
395
362
|
|
|
396
363
|
fig, ax = plt.subplots(figsize=(12, 6.75), facecolor="white")
|
|
397
364
|
ax.plot(x, "r-", label="filter")
|
|
@@ -405,6 +372,8 @@ def dplms_ge_dict(
|
|
|
405
372
|
)
|
|
406
373
|
axin.set_yticklabels("")
|
|
407
374
|
ax.indicate_inset_zoom(axin)
|
|
375
|
+
plot_dict["filter"] = fig
|
|
376
|
+
plt.close()
|
|
408
377
|
|
|
409
378
|
return out_dict, plot_dict
|
|
410
379
|
return out_dict
|