Skip to content

Commit

Permalink
Exclude non-triggering peaks when assigning main/alt peaks
Browse files Browse the repository at this point in the history
  • Loading branch information
dachengx committed Dec 16, 2024
1 parent 7138149 commit d3d47da
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 64 deletions.
4 changes: 0 additions & 4 deletions straxen/plugins/events/event_basics_som.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,3 @@ def _set_dtype_requirements(self):
("loc_y_som", np.int16, "y location of the peak(let) in the SOM"),
]
self.peak_properties = tuple(self.peak_properties)

def compute(self, events, peaks):
result = super().compute(events, peaks)
return result
98 changes: 77 additions & 21 deletions straxen/plugins/events/event_basics_vanilla.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import numba
import strax
import straxen
from .events import is_triggering


export, __all__ = strax.exporter()
Expand All @@ -17,16 +18,41 @@ class EventBasicsVanilla(strax.Plugin):
"""

__version__ = "1.3.3"
__version__ = "1.4.0"

depends_on = ("events", "peak_basics", "peak_positions", "peak_proximity")
provides = "event_basics"
data_kind = "events"

electron_drift_velocity = straxen.URLConfig(
default="cmt://electron_drift_velocity?version=ONLINE&run_id=plugin.run_id",
cache=True,
help="Vertical electron drift velocity in cm/ns (1e4 m/ms)",
trigger_min_area = straxen.URLConfig(
default=100,
type=(int, float),
help="Peaks must have more area (PE) than this to cause events",
)

trigger_max_competing = straxen.URLConfig(
default=7,
type=int,
help="Peaks must have FEWER nearby larger or slightly smaller peaks to cause events",
)

exclude_s1_as_triggering_peaks = straxen.URLConfig(
default=True,
type=bool,
help="If true exclude S1s as triggering peaks.",
)

event_s1_min_coincidence = straxen.URLConfig(
default=2,
infer_type=False,
help=(
"Event level S1 min coincidence. Should be >= "
"s1_min_coincidence in the peaklet classification"
),
)

s1_min_coincidence = straxen.URLConfig(
default=2, type=int, help="Minimum tight coincidence necessary to make an S1"
)

allow_posts2_s1s = straxen.URLConfig(
Expand All @@ -47,21 +73,18 @@ class EventBasicsVanilla(strax.Plugin):
help="Make sure alt_s2 is in max drift time starting from main S1",
)

event_s1_min_coincidence = straxen.URLConfig(
default=2,
infer_type=False,
help=(
"Event level S1 min coincidence. Should be >= s1_min_coincidence "
"in the peaklet classification"
),
)

max_drift_length = straxen.URLConfig(
default=straxen.tpc_z,
infer_type=False,
help="Total length of the TPC from the bottom of gate to the top of cathode wires [cm]",
)

electron_drift_velocity = straxen.URLConfig(
default="cmt://electron_drift_velocity?version=ONLINE&run_id=plugin.run_id",
cache=True,
help="Vertical electron drift velocity in cm/ns (1e4 m/ms)",
)

def infer_dtype(self):
# Basic event properties
self._set_posrec_save()
Expand Down Expand Up @@ -133,6 +156,11 @@ def _set_dtype_requirements(self):
)

def setup(self):
if self.s1_min_coincidence > self.event_s1_min_coincidence:
raise ValueError(
"Peak s1 coincidence requirement should be smaller "
"or equal to event_s1_min_coincidence"
)
self.drift_time_max = int(self.max_drift_length / self.electron_drift_velocity)

@staticmethod
Expand Down Expand Up @@ -237,7 +265,15 @@ def fill_result_i(self, event, peaks):
"""For a single event with the result_buffer."""
# Consider S2s first, then S1s (to enable allow_posts2_s1s = False)
# number_of_peaks=0 selects all available s2 and sort by area
largest_s2s, s2_idx = self.get_largest_sx_peaks(peaks, s_i=2, number_of_peaks=0)
largest_s2s, s2_idx = self.get_largest_sx_peaks(
peaks,
s_i=2,
trigger_min_area=self.trigger_min_area,
trigger_max_competing=self.trigger_max_competing,
exclude_s1_as_triggering_peaks=self.exclude_s1_as_triggering_peaks,
event_s1_min_coincidence=self.event_s1_min_coincidence,
number_of_peaks=0,
)

if not self.allow_posts2_s1s and len(largest_s2s):
s1_latest_time = largest_s2s[0]["time"]
Expand All @@ -247,8 +283,11 @@ def fill_result_i(self, event, peaks):
largest_s1s, s1_idx = self.get_largest_sx_peaks(
peaks,
s_i=1,
trigger_min_area=self.trigger_min_area,
trigger_max_competing=self.trigger_max_competing,
exclude_s1_as_triggering_peaks=self.exclude_s1_as_triggering_peaks,
event_s1_min_coincidence=self.event_s1_min_coincidence,
s1_before_time=s1_latest_time,
s1_min_coincidence=self.event_s1_min_coincidence,
)

if self.force_alt_s2_in_max_drift_time:
Expand Down Expand Up @@ -329,17 +368,24 @@ def set_event_properties(result, largest_s1s, largest_s2s, peaks):
peaks_before_ms2 = peaks[peaks["time"] < largest_s2s[0]["time"]]
result["area_before_main_s2"] = np.sum(peaks_before_ms2["area"])

s2peaks_before_ms2 = peaks_before_ms2[peaks_before_ms2["type"] == 2]
if len(s2peaks_before_ms2) == 0:
s2_peaks_before_ms2 = peaks_before_ms2[peaks_before_ms2["type"] == 2]
if len(s2_peaks_before_ms2) == 0:
result["large_s2_before_main_s2"] = 0
else:
result["large_s2_before_main_s2"] = np.max(s2peaks_before_ms2["area"])
result["large_s2_before_main_s2"] = np.max(s2_peaks_before_ms2["area"])
return result

@staticmethod
# @numba.njit <- works but slows if fill_events is not numbafied
def get_largest_sx_peaks(
peaks, s_i, s1_before_time=np.inf, s1_min_coincidence=0, number_of_peaks=2
peaks,
s_i,
trigger_min_area,
trigger_max_competing,
exclude_s1_as_triggering_peaks=True,
event_s1_min_coincidence=0,
s1_before_time=np.inf,
number_of_peaks=2,
):
"""Get the largest S1/S2.
Expand All @@ -348,9 +394,19 @@ def get_largest_sx_peaks(
"""
# Find all peaks of this type (S1 or S2)
s_mask = peaks["type"] == s_i
# Exclude non-triggering peaks if S2 or if (S1 and not exclude_s1_as_triggering_peaks)
if s_i == 2 or not exclude_s1_as_triggering_peaks:
s_mask &= is_triggering(
peaks,
trigger_min_area,
trigger_max_competing,
exclude_s1_as_triggering_peaks,
event_s1_min_coincidence,
)
# Extra condition for S1s
if s_i == 1:
s_mask &= peaks["time"] < s1_before_time
s_mask &= peaks["tight_coincidence"] >= s1_min_coincidence
s_mask &= peaks["tight_coincidence"] >= event_s1_min_coincidence

selected_peaks = peaks[s_mask]
s_index = np.arange(len(peaks))[s_mask]
Expand Down
93 changes: 54 additions & 39 deletions straxen/plugins/events/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,6 @@ class Events(strax.OverlapWindowPlugin):

events_seen = 0

electron_drift_velocity = straxen.URLConfig(
default="cmt://electron_drift_velocity?version=ONLINE&run_id=plugin.run_id",
cache=True,
help="Vertical electron drift velocity in cm/ns (1e4 m/ms)",
)

trigger_min_area = straxen.URLConfig(
default=100,
type=(int, float),
Expand All @@ -57,20 +51,23 @@ class Events(strax.OverlapWindowPlugin):
help="Peaks must have FEWER nearby larger or slightly smaller peaks to cause events",
)

left_event_extension = straxen.URLConfig(
default=int(0.25e6),
type=(int, float),
exclude_s1_as_triggering_peaks = straxen.URLConfig(
default=True,
type=bool,
help="If true exclude S1s as triggering peaks.",
)

event_s1_min_coincidence = straxen.URLConfig(
default=2,
infer_type=False,
help=(
"Extend events this many ns to the left from each "
"triggering peak. This extension is added to the maximum "
"drift time."
"Event level S1 min coincidence. Should be >= "
"s1_min_coincidence in the peaklet classification"
),
)

right_event_extension = straxen.URLConfig(
default=int(0.25e6),
type=(int, float),
help="Extend events this many ns to the right from each triggering peak.",
s1_min_coincidence = straxen.URLConfig(
default=2, type=int, help="Minimum tight coincidence necessary to make an S1"
)

max_drift_length = straxen.URLConfig(
Expand All @@ -79,23 +76,26 @@ class Events(strax.OverlapWindowPlugin):
help="Total length of the TPC from the bottom of gate to the top of cathode wires [cm]",
)

exclude_s1_as_triggering_peaks = straxen.URLConfig(
default=True,
type=bool,
help="If true exclude S1s as triggering peaks.",
electron_drift_velocity = straxen.URLConfig(
default="cmt://electron_drift_velocity?version=ONLINE&run_id=plugin.run_id",
cache=True,
help="Vertical electron drift velocity in cm/ns (1e4 m/ms)",
)

event_s1_min_coincidence = straxen.URLConfig(
default=2,
infer_type=False,
left_event_extension = straxen.URLConfig(
default=int(0.25e6),
type=(int, float),
help=(
"Event level S1 min coincidence. Should be >= "
"s1_min_coincidence in the peaklet classification"
"Extend events this many ns to the left from each "
"triggering peak. This extension is added to the maximum "
"drift time."
),
)

s1_min_coincidence = straxen.URLConfig(
default=2, type=int, help="Minimum tight coincidence necessary to make an S1"
right_event_extension = straxen.URLConfig(
default=int(0.25e6),
type=(int, float),
help="Extend events this many ns to the right from each triggering peak.",
)

diagnose_overlapping = straxen.URLConfig(
Expand All @@ -118,19 +118,14 @@ def get_window_size(self):
# Take a large window for safety, events can have long tails
return 10 * (self.left_event_extension + self.drift_time_max + self.right_event_extension)

def _is_triggering(self, peaks):
_is_triggering = peaks["area"] > self.trigger_min_area
_is_triggering &= peaks["n_competing"] <= self.trigger_max_competing
if self.exclude_s1_as_triggering_peaks:
_is_triggering &= peaks["type"] == 2
else:
is_not_s1 = peaks["type"] != 1
has_tc_large_enough = peaks["tight_coincidence"] >= self.event_s1_min_coincidence
_is_triggering &= is_not_s1 | has_tc_large_enough
return _is_triggering

def compute(self, peaks, start, end):
_is_triggering = self._is_triggering(peaks)
_is_triggering = is_triggering(
peaks,
self.trigger_min_area,
self.trigger_max_competing,
self.exclude_s1_as_triggering_peaks,
self.event_s1_min_coincidence,
)

triggers = peaks[_is_triggering]

Expand Down Expand Up @@ -164,3 +159,23 @@ def compute(self, peaks, start, end):
self.events_seen += len(result)

return result


@export
def is_triggering(
peaks,
trigger_min_area,
trigger_max_competing,
exclude_s1_as_triggering_peaks,
event_s1_min_coincidence,
):
_is_triggering = np.isin(peaks["type"], [0, 1, 2])
_is_triggering &= peaks["area"] > trigger_min_area
_is_triggering &= peaks["n_competing"] <= trigger_max_competing
if exclude_s1_as_triggering_peaks:
_is_triggering &= peaks["type"] == 2
else:
is_not_s1 = peaks["type"] != 1
has_tc_large_enough = peaks["tight_coincidence"] >= event_s1_min_coincidence
_is_triggering &= is_not_s1 | has_tc_large_enough
return _is_triggering

0 comments on commit d3d47da

Please sign in to comment.