Reorganize event actions to separate numba functions
This commit is contained in:
@@ -1,19 +1,37 @@
|
||||
"""
|
||||
Define an event dataformat that performs reduction actions like wavelength calculation on per-event basis.
|
||||
With large number of events these actions can be time consuming so they use numba based functions.
|
||||
"""
|
||||
import numpy as np
|
||||
import logging
|
||||
|
||||
from typing import Tuple
|
||||
from numpy.lib.recfunctions import rec_append_fields
|
||||
|
||||
from . import const
|
||||
from .event_data_types import EventDataAction, EventDatasetProtocol, append_fields, EVENT_BITMASKS
|
||||
from .helpers import filter_project_x
|
||||
from .helpers import filter_project_x, merge_frames, extract_walltime
|
||||
from .instrument import Detector
|
||||
from .options import IncidentAngle
|
||||
from .header import Header
|
||||
|
||||
class ExtractWalltime(EventDataAction):
|
||||
def perform_action(self, dataset: EventDatasetProtocol) ->None:
|
||||
# TODO: fix numba type definition after refactor
|
||||
wallTime = extract_walltime(dataset.data.events.tof,
|
||||
dataset.data.packets.start_index.astype(np.uint64),
|
||||
dataset.data.packets.Time)
|
||||
logging.debug(f' expending event stream by wallTime')
|
||||
new_events = append_fields(dataset.data.events, [('wallTime', wallTime.dtype)])
|
||||
new_events.wallTime = wallTime
|
||||
dataset.data.events = new_events
|
||||
|
||||
class MergeFrames(EventDataAction):
|
||||
def perform_action(self, dataset: EventDatasetProtocol)->None:
|
||||
tofCut = const.lamdaCut*dataset.geometry.chopperDetectorDistance/const.hdm*1e-13
|
||||
total_offset = (tofCut +
|
||||
dataset.timing.tau * (dataset.timing.ch1TriggerPhase + dataset.timing.chopperPhase/2)/180)
|
||||
dataset.data.events.tof = merge_frames(dataset.data.events.tof, tofCut, dataset.timing.tau, total_offset)
|
||||
|
||||
|
||||
class AnalyzePixelIDs(EventDataAction):
|
||||
def __init__(self, yRange: Tuple[int, int]):
|
||||
@@ -34,17 +52,6 @@ class AnalyzePixelIDs(EventDataAction):
|
||||
ana_events.mask += np.logical_not(mask)*EVENT_BITMASKS['yRange']
|
||||
d.events = ana_events
|
||||
|
||||
class TofTimeCorrection(EventDataAction):
|
||||
def __init__(self, correct_chopper_opening: bool = True):
|
||||
self.correct_chopper_opening = correct_chopper_opening
|
||||
|
||||
def perform_action(self, dataset: EventDatasetProtocol) ->None:
|
||||
d = dataset.data
|
||||
if self.correct_chopper_opening:
|
||||
d.events.tof -= ( d.events.delta / 180. ) * dataset.timing.tau
|
||||
else:
|
||||
d.events.tof -= ( dataset.geometry.kad / 180. ) * dataset.timing.tau
|
||||
|
||||
class CalculateWavelength(EventDataAction):
|
||||
def __init__(self, lambdaRange: Tuple[float, float]):
|
||||
self.lambdaRange = lambdaRange
|
||||
@@ -113,25 +120,3 @@ class FilterQzRange(EventDataAction):
|
||||
|
||||
if self.qzRange[1]<0.5:
|
||||
d.events.mask += EVENT_BITMASKS["qRange"]*((self.qzRange[0]>d.events.qz) | (d.events.qz>self.qzRange[1]))
|
||||
|
||||
class ApplyMask(EventDataAction):
|
||||
def __init__(self, bitmask_filter=None):
|
||||
self.bitmask_filter = bitmask_filter
|
||||
|
||||
def perform_action(self, dataset: EventDatasetProtocol) ->None:
|
||||
d = dataset.data
|
||||
logging.info(f' number of events: total = {d.events.shape[0]:7d}, '
|
||||
f'filtered = {(d.events.mask!=0).sum():7d}')
|
||||
if logging.getLogger().level == logging.DEBUG:
|
||||
# only run this calculation if debug level is actually active
|
||||
filtered_by_mask = {}
|
||||
for key, value in EVENT_BITMASKS.items():
|
||||
filtered_by_mask[key] = ((d.events.mask & value)!=0).sum()
|
||||
logging.debug(f" Removed by filters: {filtered_by_mask}")
|
||||
if self.bitmask_filter is None:
|
||||
d.events = d.events[d.events.mask==0]
|
||||
else:
|
||||
# remove the provided bitmask_filter bits from the events
|
||||
# this means that all bits that are set in bitmask_filter will NOT be used to filter events
|
||||
fltr = (d.events.mask & (~self.bitmask_filter)) == 0
|
||||
d.events = d.events[fltr]
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
"""
|
||||
Calculations performed on AmorEventData.
|
||||
This module contains actions that do not need the numba base helper functions. Other actions are in event_analysis
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
import numpy as np
|
||||
# from numpy.lib.recfunctions import rec_append_fields, append_fields
|
||||
|
||||
from . import const
|
||||
from .header import Header
|
||||
from .options import ExperimentConfig, MonitorType
|
||||
from .event_data_types import EventDatasetProtocol, EventDataAction, append_fields, EVENT_BITMASKS
|
||||
from .helpers import merge_frames, extract_walltime
|
||||
from .event_data_types import EventDatasetProtocol, EventDataAction, EVENT_BITMASKS
|
||||
|
||||
class ApplyPhaseOffset(EventDataAction):
|
||||
def __init__(self, chopperPhaseOffset: float):
|
||||
@@ -62,17 +60,6 @@ class CorrectChopperPhase(EventDataAction):
|
||||
dataset.data.events.tof += dataset.timing.tau*(dataset.timing.ch1TriggerPhase-dataset.timing.chopperPhase/2)/180
|
||||
|
||||
|
||||
class ExtractWalltime(EventDataAction):
|
||||
def perform_action(self, dataset: EventDatasetProtocol) ->None:
|
||||
# TODO: fix numba type definition after refactor
|
||||
wallTime = extract_walltime(dataset.data.events.tof,
|
||||
dataset.data.packets.start_index.astype(np.uint64),
|
||||
dataset.data.packets.Time)
|
||||
logging.debug(f' expending event stream by wallTime')
|
||||
new_events = append_fields(dataset.data.events, [('wallTime', wallTime.dtype)])
|
||||
new_events.wallTime = wallTime
|
||||
dataset.data.events = new_events
|
||||
|
||||
class CorrectSeriesTime(EventDataAction):
|
||||
def __init__(self, seriesStartTime):
|
||||
self.seriesStartTime = np.int64(seriesStartTime)
|
||||
@@ -146,7 +133,6 @@ class AssociatePulseWithMonitor(EventDataAction):
|
||||
return pulseCurrentS
|
||||
|
||||
|
||||
|
||||
class FilterStrangeTimes(EventDataAction):
|
||||
def perform_action(self, dataset: EventDatasetProtocol)->None:
|
||||
filter_e = np.logical_not(dataset.data.events.tof<=2*dataset.timing.tau)
|
||||
@@ -155,9 +141,35 @@ class FilterStrangeTimes(EventDataAction):
|
||||
logging.warning(f' strange times: {filter_e.sum()}')
|
||||
|
||||
|
||||
class MergeFrames(EventDataAction):
|
||||
def perform_action(self, dataset: EventDatasetProtocol)->None:
|
||||
tofCut = const.lamdaCut*dataset.geometry.chopperDetectorDistance/const.hdm*1e-13
|
||||
total_offset = (tofCut +
|
||||
dataset.timing.tau * (dataset.timing.ch1TriggerPhase + dataset.timing.chopperPhase/2)/180)
|
||||
dataset.data.events.tof = merge_frames(dataset.data.events.tof, tofCut, dataset.timing.tau, total_offset)
|
||||
class TofTimeCorrection(EventDataAction):
|
||||
def __init__(self, correct_chopper_opening: bool = True):
|
||||
self.correct_chopper_opening = correct_chopper_opening
|
||||
|
||||
def perform_action(self, dataset: EventDatasetProtocol) ->None:
|
||||
d = dataset.data
|
||||
if self.correct_chopper_opening:
|
||||
d.events.tof -= ( d.events.delta / 180. ) * dataset.timing.tau
|
||||
else:
|
||||
d.events.tof -= ( dataset.geometry.kad / 180. ) * dataset.timing.tau
|
||||
|
||||
class ApplyMask(EventDataAction):
|
||||
def __init__(self, bitmask_filter=None):
|
||||
self.bitmask_filter = bitmask_filter
|
||||
|
||||
def perform_action(self, dataset: EventDatasetProtocol) ->None:
|
||||
d = dataset.data
|
||||
logging.info(f' number of events: total = {d.events.shape[0]:7d}, '
|
||||
f'filtered = {(d.events.mask!=0).sum():7d}')
|
||||
if logging.getLogger().level == logging.DEBUG:
|
||||
# only run this calculation if debug level is actually active
|
||||
filtered_by_mask = {}
|
||||
for key, value in EVENT_BITMASKS.items():
|
||||
filtered_by_mask[key] = ((d.events.mask & value)!=0).sum()
|
||||
logging.debug(f" Removed by filters: {filtered_by_mask}")
|
||||
if self.bitmask_filter is None:
|
||||
d.events = d.events[d.events.mask==0]
|
||||
else:
|
||||
# remove the provided bitmask_filter bits from the events
|
||||
# this means that all bits that are set in bitmask_filter will NOT be used to filter events
|
||||
fltr = (d.events.mask & (~self.bitmask_filter)) == 0
|
||||
d.events = d.events[fltr]
|
||||
|
||||
@@ -240,7 +240,7 @@ class ExperimentConfig(ArgParsable):
|
||||
},
|
||||
)
|
||||
|
||||
incidentAngle: str = field(
|
||||
incidentAngle: IncidentAngle = field(
|
||||
default=IncidentAngle.alphaF,
|
||||
metadata={
|
||||
'short': 'ai',
|
||||
|
||||
@@ -48,32 +48,32 @@ class AmorReduction:
|
||||
self.normevent_actions = eh.ApplyPhaseOffset(self.experiment_config.chopperPhaseOffset)
|
||||
self.normevent_actions |= eh.CorrectChopperPhase()
|
||||
if self.experiment_config.monitorType in [MonitorType.proton_charge, MonitorType.debug]:
|
||||
self.normevent_actions |= eh.ExtractWalltime()
|
||||
self.normevent_actions |= ea.ExtractWalltime()
|
||||
self.normevent_actions |= eh.AssociatePulseWithMonitor(self.experiment_config.monitorType,
|
||||
self.experiment_config.lowCurrentThreshold)
|
||||
self.normevent_actions |= eh.FilterStrangeTimes()
|
||||
self.normevent_actions |= eh.MergeFrames()
|
||||
self.normevent_actions |= ea.MergeFrames()
|
||||
self.normevent_actions |= ea.AnalyzePixelIDs(self.experiment_config.yRange)
|
||||
self.normevent_actions |= ea.TofTimeCorrection(self.experiment_config.incidentAngle==IncidentAngle.alphaF)
|
||||
self.normevent_actions |= eh.TofTimeCorrection(self.experiment_config.incidentAngle==IncidentAngle.alphaF)
|
||||
self.normevent_actions |= ea.CalculateWavelength(self.experiment_config.lambdaRange)
|
||||
self.normevent_actions |= ea.ApplyMask()
|
||||
self.normevent_actions |= eh.ApplyMask()
|
||||
# Actions on datasets not used for normalization
|
||||
self.dataevent_actions = eh.ApplyPhaseOffset(self.experiment_config.chopperPhaseOffset)
|
||||
self.dataevent_actions |= eh.ApplyParameterOverwrites(self.experiment_config) # some actions use instrument parameters, change before that
|
||||
self.dataevent_actions |= eh.CorrectChopperPhase()
|
||||
self.dataevent_actions |= eh.ExtractWalltime()
|
||||
self.dataevent_actions |= ea.ExtractWalltime()
|
||||
self.dataevent_time_correction = eh.CorrectSeriesTime(0) # will be set from first dataset
|
||||
self.dataevent_actions |= self.dataevent_time_correction
|
||||
self.dataevent_actions |= eh.AssociatePulseWithMonitor(self.experiment_config.monitorType,
|
||||
self.experiment_config.lowCurrentThreshold)
|
||||
self.dataevent_actions |= eh.FilterStrangeTimes()
|
||||
self.dataevent_actions |= eh.MergeFrames()
|
||||
self.dataevent_actions |= ea.MergeFrames()
|
||||
self.dataevent_actions |= ea.AnalyzePixelIDs(self.experiment_config.yRange)
|
||||
self.dataevent_actions |= ea.TofTimeCorrection(self.experiment_config.incidentAngle==IncidentAngle.alphaF)
|
||||
self.dataevent_actions |= eh.TofTimeCorrection(self.experiment_config.incidentAngle==IncidentAngle.alphaF)
|
||||
self.dataevent_actions |= ea.CalculateWavelength(self.experiment_config.lambdaRange)
|
||||
self.dataevent_actions |= ea.CalculateQ(self.experiment_config.incidentAngle)
|
||||
self.dataevent_actions |= ea.FilterQzRange(self.reduction_config.qzRange)
|
||||
self.dataevent_actions |= ea.ApplyMask()
|
||||
self.dataevent_actions |= eh.ApplyMask()
|
||||
|
||||
self.grid = LZGrid(self.reduction_config.qResolution, self.reduction_config.qzRange)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user