Commit e442266e authored by Jens Kroeger's avatar Jens Kroeger
Browse files

resolved merge conflicts in EventLoaderATLASpix

parents ca9671c0 9d4d7dbc
......@@ -70,6 +70,7 @@ Detector::Detector(const Configuration& config) : m_role(DetectorRole::NONE) {
}
m_detectorType = config.get<std::string>("type");
std::transform(m_detectorType.begin(), m_detectorType.end(), m_detectorType.begin(), ::tolower);
m_timingOffset = config.get<double>("time_offset", 0.0);
m_roi = config.getMatrix<int>("roi", std::vector<std::vector<int>>());
......
......@@ -23,6 +23,8 @@ EventLoaderEUDAQ2::EventLoaderEUDAQ2(Configuration config, std::shared_ptr<Detec
m_adjust_event_times = m_config.getMatrix<std::string>("adjust_event_times", {});
m_buffer_depth = m_config.get<int>("buffer_depth", 0);
m_inclusive = m_config.get("inclusive", true);
// Forward all settings to EUDAQ
// WARNING: the EUDAQ Configuration class is not very flexible and e.g. booleans have to be passed as 1 and 0.
eudaq::Configuration cfg;
......@@ -133,6 +135,7 @@ void EventLoaderEUDAQ2::initialise() {
std::shared_ptr<eudaq::StandardEvent> EventLoaderEUDAQ2::get_next_sorted_std_event() {
// Refill the event buffer if necessary:
while(static_cast<int>(sorted_events_.size()) < m_buffer_depth) {
LOG(DEBUG) << "Filling buffer with new event.";
// fill buffer with new std event:
......@@ -167,16 +170,13 @@ std::shared_ptr<eudaq::StandardEvent> EventLoaderEUDAQ2::get_next_std_event() {
if(events_.empty()) {
events_.push_back(new_event);
}
// FIXME get TLU events with trigger IDs before Ni - sort by name, reversed
sort(events_.begin(), events_.end(), [](const eudaq::EventSPC& a, const eudaq::EventSPC& b) -> bool {
return a->GetDescription() > b->GetDescription();
});
}
LOG(TRACE) << "Buffer contains " << events_.size() << " (sub-) events:";
for(int i = 0; i < static_cast<int>(events_.size()); i++) {
LOG(TRACE) << " (sub-) event " << i << " is a " << events_[static_cast<long unsigned int>(i)]->GetDescription();
for(auto& evt : events_) {
LOG(TRACE) << " (sub-) event of type " << evt->GetDescription();
}
// Retrieve first and remove from buffer:
auto event = events_.front();
events_.erase(events_.begin());
......@@ -216,27 +216,31 @@ void EventLoaderEUDAQ2::retrieve_event_tags(const eudaq::EventSPC evt) {
}
}
}
EventLoaderEUDAQ2::EventPosition EventLoaderEUDAQ2::is_within_event(std::shared_ptr<Clipboard> clipboard,
std::shared_ptr<eudaq::StandardEvent> evt) {
Event::Position EventLoaderEUDAQ2::is_within_event(std::shared_ptr<Clipboard> clipboard,
std::shared_ptr<eudaq::StandardEvent> evt) const {
// Check if this event has timestamps available:
if(evt->GetTimeBegin() == 0) {
LOG(DEBUG) << evt->GetDescription() << ": Event has no timestamp, comparing trigger number";
LOG(DEBUG) << evt->GetDescription() << ": Event has no timestamp, comparing trigger IDs";
// If there is no event defined yet or the trigger number is unkown, there is little we can do:
if(!clipboard->isEventDefined() || !clipboard->getEvent()->hasTriggerID(evt->GetTriggerN())) {
LOG(DEBUG) << "Trigger ID " << evt->GetTriggerN() << " not found in current event.";
return EventPosition::UNKNOWN;
// If there is no event defined yet, there is little we can do:
if(!clipboard->isEventDefined()) {
LOG(DEBUG) << "No Corryvreckan event defined - cannot define without timetamps.";
return Event::Position::UNKNOWN;
}
// Store trigger timestamp in event:
auto trigger_time = clipboard->getEvent()->getTriggerTime(evt->GetTriggerN());
LOG(DEBUG) << "Assigning trigger time " << Units::display(trigger_time, {"us", "ns"}) << " to event with trigger ID "
<< evt->GetTriggerN();
// Set EUDAQ StandardEvent timestamp in picoseconds:
evt->SetTimeBegin(static_cast<uint64_t>(trigger_time * 1000));
evt->SetTimeEnd(static_cast<uint64_t>(trigger_time * 1000));
// Get position of this time frame with respect to the defined event:
auto trigger_position = clipboard->getEvent()->getTriggerPosition(evt->GetTriggerN());
if(trigger_position == Event::Position::BEFORE) {
LOG(DEBUG) << "Trigger ID " << evt->GetTriggerN() << " before triggers registered in Corryvreckan event";
} else if(trigger_position == Event::Position::AFTER) {
LOG(DEBUG) << "Trigger ID " << evt->GetTriggerN() << " after triggers registered in Corryvreckan event";
} else if(trigger_position == Event::Position::UNKNOWN) {
LOG(DEBUG) << "Trigger ID " << evt->GetTriggerN() << " within Corryvreckan event range but not registered";
} else {
LOG(DEBUG) << "Trigger ID " << evt->GetTriggerN() << " found in Corryvreckan event";
}
return trigger_position;
}
// Read time from EUDAQ2 event and convert from picoseconds to nanoseconds:
......@@ -254,7 +258,7 @@ EventLoaderEUDAQ2::EventPosition EventLoaderEUDAQ2::is_within_event(std::shared_
if(event_start < m_skip_time) {
LOG(DEBUG) << "Event start before requested skip time: " << Units::display(event_start, {"us", "ns"}) << " < "
<< Units::display(m_skip_time, {"us", "ns"});
return EventPosition::BEFORE;
return Event::Position::BEFORE;
}
double shift_start = 0;
......@@ -280,19 +284,14 @@ EventLoaderEUDAQ2::EventPosition EventLoaderEUDAQ2::is_within_event(std::shared_
LOG(DEBUG) << "Corryvreckan event found on clipboard.";
}
double clipboard_start = clipboard->getEvent()->start();
double clipboard_end = clipboard->getEvent()->end();
// if(event_start < clipboard_start) { // we still need to discuss about the logic here!
if(event_end < clipboard_start) {
// Get position of this time frame with respect to the defined event:
auto position = clipboard->getEvent()->getFramePosition(event_start, event_end, m_inclusive);
if(position == Event::Position::BEFORE) {
LOG(DEBUG) << "Event start before Corryvreckan event: " << Units::display(event_start, {"us", "ns"}) << " < "
<< Units::display(clipboard_start, {"us", "ns"});
return EventPosition::BEFORE;
// } else if(clipboard_end < event_end) { // we still need to discuss about the logic here!
} else if(clipboard_end < event_start) {
<< Units::display(clipboard->getEvent()->start(), {"us", "ns"});
} else if(position == Event::Position::AFTER) {
LOG(DEBUG) << "Event end after Corryvreckan event: " << Units::display(event_end, {"us", "ns"}) << " > "
<< Units::display(clipboard_end, {"us", "ns"});
return EventPosition::AFTER;
<< Units::display(clipboard->getEvent()->end(), {"us", "ns"});
} else {
// check if event has valid trigger ID (flag = 0x10):
if(evt->IsFlagTrigger()) {
......@@ -301,72 +300,118 @@ EventLoaderEUDAQ2::EventPosition EventLoaderEUDAQ2::is_within_event(std::shared_
LOG(DEBUG) << "Stored trigger ID " << evt->GetTriggerN() << " at "
<< Units::display(event_start - shift_start, {"us", "ns"});
}
return EventPosition::DURING;
}
return position;
}
std::shared_ptr<PixelVector> EventLoaderEUDAQ2::get_pixel_data(std::shared_ptr<eudaq::StandardEvent> evt) {
std::shared_ptr<PixelVector> EventLoaderEUDAQ2::get_pixel_data(std::shared_ptr<eudaq::StandardEvent> evt,
int plane_id) const {
auto pixels = std::make_shared<PixelVector>();
// Loop over all planes, select the relevant detector:
for(size_t i_plane = 0; i_plane < evt->NumPlanes(); i_plane++) {
auto plane = evt->GetPlane(i_plane);
// No plane found:
if(plane_id < 0) {
return pixels;
}
// Concatenate plane name according to naming convention: sensor_type + "_" + int
auto plane_name = plane.Sensor() + "_" + std::to_string(plane.ID());
auto detector_name = m_detector->name();
// Convert to lower case before string comparison to avoid errors by the user:
std::transform(plane_name.begin(), plane_name.end(), plane_name.begin(), ::tolower);
std::transform(detector_name.begin(), detector_name.end(), detector_name.begin(), ::tolower);
LOG(TRACE) << plane_name << " (" << i_plane << " out of " << evt->NumPlanes() << ") with " << plane.HitPixels()
<< " hit pixels";
auto plane = evt->GetPlane(static_cast<size_t>(plane_id));
// Concatenate plane name according to naming convention: sensor_type + "_" + int
auto plane_name = plane.Sensor() + "_" + std::to_string(plane.ID());
auto detector_name = m_detector->name();
// Convert to lower case before string comparison to avoid errors by the user:
std::transform(plane_name.begin(), plane_name.end(), plane_name.begin(), ::tolower);
std::transform(detector_name.begin(), detector_name.end(), detector_name.begin(), ::tolower);
LOG(TRACE) << plane_name << " (ID " << plane_id << ") with " << plane.HitPixels() << " pixel hits";
// Loop over all hits and add to pixels vector:
for(unsigned int i = 0; i < plane.HitPixels(); i++) {
auto col = static_cast<int>(plane.GetX(i));
auto row = static_cast<int>(plane.GetY(i));
auto raw = static_cast<int>(plane.GetPixel(i)); // generic pixel raw value (could be ToT, ADC, ...)
auto ts = static_cast<double>(plane.GetTimestamp(i)) / 1000 + m_detector->timingOffset();
if(col >= m_detector->nPixels().X() || row >= m_detector->nPixels().Y()) {
LOG(WARNING) << "Pixel address " << col << ", " << row << " is outside of pixel matrix.";
}
if(detector_name != plane_name) {
LOG(TRACE) << "Wrong plane: " << detector_name << "!=" << plane_name << ". Continue.";
if(m_detector->masked(col, row)) {
LOG(TRACE) << "Masking pixel (col, row) = (" << col << ", " << row << ")";
continue;
} else {
LOG(TRACE) << "Storing (col, row) = (" << col << ", " << row << ") from EUDAQ2 event data";
}
LOG(DEBUG) << "Found correct plane.";
// Loop over all hits and add to pixels vector:
for(unsigned int i = 0; i < plane.HitPixels(); i++) {
auto col = static_cast<int>(plane.GetX(i));
auto row = static_cast<int>(plane.GetY(i));
auto raw = static_cast<int>(plane.GetPixel(i)); // generic pixel raw value (could be ToT, ADC, ...)
auto ts = static_cast<double>(plane.GetTimestamp(i)) / 1000 + m_detector->timingOffset();
// when calibration is not available, set charge = raw
Pixel* pixel = new Pixel(m_detector->name(), col, row, raw, raw, ts);
if(col >= m_detector->nPixels().X() || row >= m_detector->nPixels().Y()) {
LOG(WARNING) << "Pixel address " << col << ", " << row << " is outside of pixel matrix.";
}
hitmap->Fill(col, row);
hPixelTimes->Fill(static_cast<double>(Units::convert(ts, "ms")));
hPixelTimes_long->Fill(static_cast<double>(Units::convert(ts, "s")));
hPixelRawValues->Fill(raw);
LOG(DEBUG) << "Read pixel (col, row) = (" << col << ", " << row << ") from EUDAQ2 event data (before masking).";
if(m_detector->masked(col, row)) {
LOG(TRACE) << "Masked pixel (col, row) = (" << col << ", " << row << ")";
continue;
}
pixels->push_back(pixel);
}
hPixelMultiplicity->Fill(static_cast<int>(pixels->size()));
LOG(DEBUG) << m_detector->name() << ": Plane contains " << pixels->size() << " pixels";
// when calibration is not available, set charge = raw
Pixel* pixel = new Pixel(m_detector->name(), col, row, raw, raw, ts);
return pixels;
}
bool EventLoaderEUDAQ2::filter_detectors(std::shared_ptr<eudaq::StandardEvent> evt, int& plane_id) const {
// Check if the detector type matches the currently processed detector type:
auto detector_type = evt->GetDetectorType();
std::transform(detector_type.begin(), detector_type.end(), detector_type.begin(), ::tolower);
// Fall back to parsing the description if not set:
if(detector_type.empty()) {
LOG(TRACE) << "Using fallback comparison with EUDAQ2 event description";
auto description = evt->GetDescription();
std::transform(description.begin(), description.end(), description.begin(), ::tolower);
if(description.find(m_detector->type()) == std::string::npos) {
LOG(DEBUG) << "Ignoring event because description doesn't match type " << m_detector->type() << ": "
<< description;
return false;
}
} else if(detector_type != m_detector->type()) {
LOG(DEBUG) << "Ignoring event because detector type doesn't match: " << detector_type;
return false;
}
// To the best of our knowledge, this is the detector we are looking for.
LOG(DEBUG) << "Found matching event for detector type " << m_detector->type();
if(evt->NumPlanes() == 0) {
return true;
}
// Check if we can identify the detector itself among the planes:
for(size_t i_plane = 0; i_plane < evt->NumPlanes(); i_plane++) {
auto plane = evt->GetPlane(i_plane);
hitmap->Fill(col, row);
hPixelTimes->Fill(static_cast<double>(Units::convert(ts, "ms")));
hPixelTimes_long->Fill(static_cast<double>(Units::convert(ts, "s")));
hPixelRawValues->Fill(raw);
// Concatenate plane name according to naming convention: sensor_type + "_" + int
auto plane_name = plane.Sensor() + "_" + std::to_string(plane.ID());
auto detector_name = m_detector->name();
// Convert to lower case before string comparison to avoid errors by the user:
std::transform(plane_name.begin(), plane_name.end(), plane_name.begin(), ::tolower);
std::transform(detector_name.begin(), detector_name.end(), detector_name.begin(), ::tolower);
pixels->push_back(pixel);
if(detector_name == plane_name) {
plane_id = static_cast<int>(i_plane);
LOG(DEBUG) << "Found matching plane in event for detector " << m_detector->name();
return true;
}
hPixelMultiplicity->Fill(static_cast<int>(pixels->size()));
LOG(DEBUG) << m_detector->name() << ": Plane contains " << pixels->size() << " pixels";
}
return pixels;
// Detector not found among planes of this event
LOG(DEBUG) << "Ignoring event because no matching plane could be found for detector " << m_detector->name();
return false;
}
StatusCode EventLoaderEUDAQ2::run(std::shared_ptr<Clipboard> clipboard) {
auto pixels = std::make_shared<PixelVector>();
EventPosition current_position = EventPosition::UNKNOWN;
Event::Position current_position = Event::Position::UNKNOWN;
while(1) {
// Retrieve next event from file/buffer:
if(!event_) {
......@@ -383,22 +428,29 @@ StatusCode EventLoaderEUDAQ2::run(std::shared_ptr<Clipboard> clipboard) {
}
}
// Filter out "wrong" detectors and store plane ID if found:
int plane_id = -1;
if(!filter_detectors(event_, plane_id)) {
event_.reset();
continue;
}
// Check if this event is within the currently defined Corryvreckan event:
current_position = is_within_event(clipboard, event_);
if(current_position == EventPosition::DURING) {
if(current_position == Event::Position::DURING) {
LOG(DEBUG) << "Is within current Corryvreckan event, storing data";
// Store data on the clipboard
auto new_pixels = get_pixel_data(event_);
auto new_pixels = get_pixel_data(event_, plane_id);
pixels->insert(pixels->end(), new_pixels->begin(), new_pixels->end());
}
// If this event was after the current event, stop reading:
if(current_position == EventPosition::AFTER) {
// If this event was after the current event or if we have not enough information, stop reading:
if(current_position == Event::Position::AFTER || current_position == Event::Position::UNKNOWN) {
break;
}
// Do not fill if current_position == EventPosition::AFTER to avoid double-counting!
// Do not fill if current_position == Event::Position::AFTER to avoid double-counting!
// Converting EUDAQ2 picoseconds into Corryvreckan nanoseconds:
hEudaqEventStart->Fill(static_cast<double>(event_->GetTimeBegin()) / 1e9); // here convert from ps to ms
hEudaqEventStart_long->Fill(static_cast<double>(event_->GetTimeBegin()) / 1e12); // here convert from ps to seconds
......
......@@ -11,13 +11,14 @@
* Refer to the User's Manual for more details.
*/
#include <iostream>
#include <vector>
#include <TCanvas.h>
#include <TH1F.h>
#include <TH2F.h>
#include <TProfile.h>
#include <iostream>
#include "core/module/Module.hpp"
#include "eudaq/FileReader.hh"
#include "eudaq/StandardEvent.hh"
......@@ -34,13 +35,6 @@ namespace corryvreckan {
*/
class EventLoaderEUDAQ2 : public Module {
enum class EventPosition {
UNKNOWN, // StandardEvent position unknown
BEFORE, // StandardEvent is before current event
DURING, // StandardEvent is during current event
AFTER, // StandardEvent is after current event
};
class EndOfFile : public Exception {};
public:
......@@ -77,7 +71,8 @@ namespace corryvreckan {
* @param evt The EUDAQ StandardEvent to check
* @return Position of the StandardEvent with respect to the current Corryvreckan event
*/
EventPosition is_within_event(std::shared_ptr<Clipboard> clipboard, std::shared_ptr<eudaq::StandardEvent> evt);
Event::Position is_within_event(std::shared_ptr<Clipboard> clipboard,
std::shared_ptr<eudaq::StandardEvent> evt) const;
/**
* @brief Helper function to retrieve event tags and creating plots from them
......@@ -88,23 +83,35 @@ namespace corryvreckan {
/**
* @brief Store pixel data from relevant detectors on the clipboard
* @param evt StandardEvent to read the pixel data from
* @param plane_id ID of the EUDAQ2 StandardEvent plane to be read and stored
* @return Vector of pointers to pixels read from this event
*/
std::shared_ptr<PixelVector> get_pixel_data(std::shared_ptr<eudaq::StandardEvent> evt);
std::shared_ptr<PixelVector> get_pixel_data(std::shared_ptr<eudaq::StandardEvent> evt, int plane_id) const;
/**
* @brief Filter the incoming EUDAQ2 events for the correct detector and detector type
* @param evt The EUDAQ2 StdEvt to be scrutinized
* @param plane_id If found within the event, the plane ID if the detector is stored in the reference
* @return Verdict whether this is the detector we are looking for or not
*/
bool filter_detectors(std::shared_ptr<eudaq::StandardEvent> evt, int& plane_id) const;
std::shared_ptr<Detector> m_detector;
std::string m_filename{};
bool m_get_time_residuals{};
bool m_get_tag_vectors{};
bool m_ignore_bore{};
bool m_inclusive;
double m_skip_time{};
Matrix<std::string> m_adjust_event_times;
int m_buffer_depth;
// EUDAQ file reader instance to retrieve data from
eudaq::FileReaderUP reader_;
// Buffer of undecoded EUDAQ events
std::vector<eudaq::EventSPC> events_;
// Currently processed decoded EUDAQ StandardEvent:
std::shared_ptr<eudaq::StandardEvent> event_;
......
......@@ -15,8 +15,8 @@ The first detector that appears in the configuration defines the event window to
In the example below this is the CLICpix2.
If the data of multiple detectors is stored in the same file as sub-events, it must be ensured that the event defining the time frame is processed first.
Currently, this is not implemented in a generic way (yet): the sub-events are sorted in reverse alphabetic order and then processed.
This works if dealing with TLU (`TluRawDataEvent`) and Mimosa26 (`NiRawDataEvent`).
This is achieved by instantiating two event loaders in the desired order and providing them with the same input data file.
The individual (sub-) events are compared against the detector type.
For each event, the algorithm checks for an event on the clipboard.
If none is available, the current event defines the event on the clipboard.
......@@ -57,7 +57,7 @@ The decoder promises to
* not return any event before a possible T0 signal in the data.
* return the smallest possible granularity of data in time either as even or as sub-events within one event.
* always return valid event time stamps. If the device does not have timestamps, it should return zero for the beginning of the event and have a valid trigger number set.
* return events in a the correct time order
* provide the detector type via the `GetDetectorType()` function in the decoded StandardEvent.
### Configuring EUDAQ2 Event Converters
......@@ -69,6 +69,7 @@ Also, more complex constructs such as arrays or matrices read by the Corryvrecka
### Parameters
* `file_name`: File name of the EUDAQ2 raw data file. This parameter is mandatory.
* `inclusive`: Boolean parameter to select whether new data should be compared to the existing Corryvreckan event in inclusive or exclusive mode. The inclusive interpretation will allow new data to be added to the event as soon as there is some overlap between the data time frame and the existing event, i.e. as soon as the end of the time frame is later than the event start or as soon as the time frame start is before the event end. In the exclusive mode, the frame will only be added to the existing event,if its start and end are both within the defined event.
* `skip_time`: Time that can be skipped at the start of a run. Default is `0ms`.
* `get_time_residuals`: Boolean to change if time residual plots should be created. Default value is `false`.
* `get_tag_vectors`: Boolean to enable creation of EUDAQ2 event tag histograms. Default value is `false`.
......
......@@ -431,7 +431,7 @@ bool EventLoaderTimepix3::loadData(std::shared_ptr<Clipboard> clipboard,
// Stop looking at data if the signal is after the current event window
// (and rewind the file
// reader so that we start with this signal next event)
if(timestamp > event->end()) {
if(event->getTimestampPosition(timestamp) == Event::Position::AFTER) {
(*m_file_iterator)->seekg(-1 * static_cast<int>(sizeof(pixdata)), std::ios_base::cur);
LOG(TRACE) << "Signal has a time beyond the current event: " << Units::display(timestamp, "ns");
break;
......@@ -557,9 +557,10 @@ bool EventLoaderTimepix3::loadData(std::shared_ptr<Clipboard> clipboard,
// Convert final timestamp into ns and add the timing offset (in nano seconds) from the detectors file (if any)
const double timestamp = static_cast<double>(time) / (4096. / 25.) + m_detector->timingOffset();
auto position = event->getTimestampPosition(timestamp);
// Ignore pixel data if it is before the "eventStart" read from the clipboard storage:
if(timestamp < event->start()) {
if(position == Event::Position::BEFORE) {
LOG(TRACE) << "Skipping pixel, is before event window (" << Units::display(timestamp, {"s", "us", "ns"})
<< " < " << Units::display(event->start(), {"s", "us", "ns"}) << ")";
continue;
......@@ -567,7 +568,7 @@ bool EventLoaderTimepix3::loadData(std::shared_ptr<Clipboard> clipboard,
// Stop looking at data if the pixel is after the current event window
// (and rewind the file reader so that we start with this pixel next event)
if(timestamp > event->end()) {
if(position == Event::Position::AFTER) {
LOG(DEBUG) << "Stopping processing event, pixel is after "
"event window ("
<< Units::display(timestamp, {"s", "us", "ns"}) << " > "
......
......@@ -8,6 +8,13 @@ namespace corryvreckan {
class Event : public Object {
public:
enum class Position {
UNKNOWN, // StandardEvent position unknown
BEFORE, // StandardEvent is before current event
DURING, // StandardEvent is during current event
AFTER, // StandardEvent is after current event
};
// Constructors and destructors
Event() = default;
Event(double start, double end, std::map<uint32_t, double> trigger_list = std::map<uint32_t, double>())
......@@ -41,6 +48,96 @@ namespace corryvreckan {
**/
double getTriggerTime(uint32_t trigger_id) const { return trigger_list_.find(trigger_id)->second; }
/**
* @brief Returns position of a timestamp relative to the current event
*
* This function allows to assess whether a timestamp lies before, during or after the defined event.
* @param frame_start Timestamp to get position for
* @return Position of the given timestamp with respect to the defined event.
*/
Position getTimestampPosition(double timestamp) {
if(timestamp < start()) {
return Position::BEFORE;
} else if(end() < timestamp) {
return Position::AFTER;
} else {
return Position::DURING;
}
}
/**
* @brief Returns position of a time frame defined by a start and end point relative to the current event
*
* This function allows to assess whether a time frame lies before, during or after the defined event. There are two
* options of interpretation. The inclusive interpretation will return "during" as soon as there is some overlap
* between the frame and the event, i.e. as soon as the end of the frame is later than the event start or as soon as
* the frame start is before the event end. In the exclusive mode, the frame will be classified as "during" only if
* start and end are both within the defined event. The function returns UNKNOWN if the end of the given time frame
* is before its start.
* @param frame_start Start timestamp of the frame
* @param frame_end End timestamp of the frame
* @param inclusive Boolean to select inclusive or exclusive mode
* @return Position of the given time frame with respect to the defined event.
*/
Position getFramePosition(double frame_start, double frame_end, bool inclusive = true) {
// The frame is ill-defined, we have no idea what to do with this data:
if(frame_end < frame_start) {
return Position::UNKNOWN;
}
if(inclusive) {
// Return DURING if there is any overlap
if(frame_end < start()) {
return Position::BEFORE;
} else if(end() < frame_start) {
return Position::AFTER;
} else {
return Position::DURING;
}
} else {
// Return DURING only if fully covered
if(frame_start < start()) {
return Position::BEFORE;
} else if(end() < frame_end) {
return Position::AFTER;
} else {
return Position::DURING;
}
}
}
/**
* @brief Returns position of a given trigger ID with respect to the currently defined event.
*
* If the given trigger ID is smaller than the smallest trigger ID known to the event, BEFORE is returned. If the
* trigger ID is larger than the largest know ID, AFTER is returned. If the trigger ID is known to the event, DURING
* is returned. UNKNOWN is returned if either no trigger ID is known to the event or if the given ID lies between the
* smallest and larges known ID but is not part of the event.
* @param trigger_id Given trigger ID to check
* @return Position of the given trigger ID with respect to the defined event.
*/
Position getTriggerPosition(uint32_t trigger_id) const {
// If we have no triggers we cannot make a statement:
if(trigger_list_.empty()) {
return Position::UNKNOWN;
}
if(hasTriggerID(trigger_id)) {
return Position::DURING;
} else if(trigger_list_.upper_bound(trigger_id) == trigger_list_.begin()) {
// Upper bound returns first element that is greater than the given key - in this case, the first map element
// is greater than the provided trigger number - which consequently is before the event.
return Position::BEFORE;
} else if(trigger_list_.lower_bound(trigger_id) == trigger_list_.end()) {
// Lower bound returns the first element that is *not less* than the given key - in this case, even the last
// map element is less than the trigger number - which consequently is after the event.
return Position::AFTER;
} else {
// We have not enough information to provide position information.
return Position::UNKNOWN;
}
}
std::map<uint32_t, double> triggerList() const { return trigger_list_; }
/**
......@@ -54,7 +151,7 @@ namespace corryvreckan {
std::map<uint32_t, double> trigger_list_{};
// ROOT I/O class definition - update version number when you change this class!
ClassDefOverride(Event, 4)
ClassDefOverride(Event, 5)
};
} // namespace corryvreckan
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment