Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Online veto intervals fix #1331

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion straxen/contexts.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ def xenonnt_online(
straxen.OnlineMonitor(
readonly=not we_are_the_daq,
take_only=(
"veto_intervals",
"online_veto_intervals",
"online_peak_monitor",
"event_basics",
"online_monitor_nv",
Expand Down
3 changes: 3 additions & 0 deletions straxen/plugins/veto_intervals/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
from . import veto_intervals
from .veto_intervals import *

from . import online_veto_intervals
from .online_veto_intervals import *
108 changes: 108 additions & 0 deletions straxen/plugins/veto_intervals/online_veto_intervals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import numpy as np
import strax
import straxen

export, __all__ = strax.exporter()


# ### Veto hardware ###:
# V1495 busy veto module:
# Generates a 25 ns NIM pulse whenever a veto begins and a 25 ns NIM signal when it ends.
# A new start signal can occur only after the previous busy instance ended.
# 1ms (1e6 ns) - minimum busy veto length, or until the board clears its memory

# DDC10 High Energy Veto:
# 10ms (1e7 ns) - fixed HE veto length in XENON1T DDC10,
# in XENONnT it will be calibrated based on the length of large S2 SE tails
# The start/stop signals for the HEV are generated by the V1495 board


@export
class OnlineVetoIntervals(strax.OverlapWindowPlugin):
"""Find pairs of veto start and veto stop signals and the veto.

duration between them:
- busy_* <= V1495 busy veto for tpc channels
- busy_he_* <= V1495 busy veto for high energy tpc channels
- hev_* <= DDC10 hardware high energy veto
- straxen_deadtime <= special case of deadtime introduced by the
DAQReader-plugin

"""

__version__ = "0.0.1"
depends_on = "veto_intervals"
provides = "online_veto_intervals"
data_kind = "veto_intervals"

# Save the data only when it is requested explicitly
save_when = strax.SaveWhen.EXPLICIT

# This option is just showing where the OverlapWindowPlugin fails.
# We need to buffer the entire run in order not to run into chunking
# issues. A better solution would be using
# github.com/AxFoundation/strax/pull/654
max_veto_window = straxen.URLConfig(
default=int(7.2e12),
track=True,
type=int,
help=(
"Maximum separation between veto stop and start pulses [ns]. "
"Set to be >> than the max duration of the run to be able to "
"fully store one run into buffer since aqmon-hits are not "
"sorted by endtime"
),
)

online_max_bytes = straxen.URLConfig(
default=6e6, track=True, help="Maximum amount of bytes of data for MongoDB document"
)

def infer_dtype(self):
dtype = [
(("veto interval [ns]", "veto_interval"), np.int64),
(("veto signal type", "veto_type"), np.str_("U30")),
(("cumulative time of the veto interval [ns]", "cumulative_deadtime"), np.float64),
]
dtype += strax.time_fields
return dtype

def compute(self, veto_intervals, start, end):

# Calculate the cumulative deadtime for the entire chunk
cumulative_deadtime = self._data_to_ms_cumsum(veto_intervals)

if veto_intervals.nbytes > self.online_max_bytes:

# Calculate fraction of the data that can be kept,
# to reduce datasize. Randomly keep a fraction of the data
new_len = int(len(veto_intervals) / veto_intervals.nbytes * self.online_max_bytes)
idx = np.random.choice(np.arange(len(veto_intervals)), replace=False, size=new_len)
veto_intervals = veto_intervals[np.sort(idx)]

# Only keep the cumulative deadtime for the kept data indices
cumulative_deadtime = cumulative_deadtime[np.sort(idx)]

result = np.zeros(len(veto_intervals), dtype=self.dtype)
result["veto_interval"] = veto_intervals["veto_interval"]
result["veto_type"] = veto_intervals["veto_type"]
result["cumulative_deadtime"] = cumulative_deadtime
result["time"] = veto_intervals["time"]
result["endtime"] = veto_intervals["endtime"]

# If the final data array is still too large, we randomly sample again
# up to 10MB
if result.nbytes > self.online_max_bytes and result.nbytes < 10e6:
new_len = int(len(result) / result.nbytes * self.online_max_bytes)
idx = np.random.choice(np.arange(len(result)), replace=False, size=new_len)
result = result[np.sort(idx)]

return result

def get_window_size(self):
# Give a very wide window
return self.max_veto_window

@staticmethod
def _data_to_ms_cumsum(data):
return np.cumsum(data["veto_interval"]) / 1e6