|
| 1 | +/** |
| 2 | + * @file sbnobj/Common/PMT/Data/PMTBeamSignal.cxx |
| 3 | + * @brief Holds the event-by-event RWM or EW times |
| 4 | + * @author Anna Heggestuen (aheggest@colostate.edu), adapted from M. Vicenzi in https://github.com/SBNSoftware/icaruscode/pull/751 |
| 5 | + * @date May 19, 2025 |
| 6 | + * @see sbnobj/Common/PMT/Data/PMTBeamSignal.h |
| 7 | + */ |
| 8 | + |
| 9 | +//library header |
| 10 | +#include "sbnobj/Common/PMT/Data/PMTBeamSignal.hh" |
| 11 | + |
| 12 | +// framework libraries |
| 13 | +#include "messagefacility/MessageLogger/MessageLogger.h" |
| 14 | + |
| 15 | + |
| 16 | +// ----------------------------------------------------------------------------- |
| 17 | +void sbn::timing::SelectFirstOpHitByTime(const recob::OpHit* const hit, |
| 18 | + std::map<int, double> &risemap) |
| 19 | +{ |
| 20 | + const int ch = hit->OpChannel(); |
| 21 | + double ts = hit->StartTime(); |
| 22 | + double tr = hit->RiseTime(); |
| 23 | + // select the first ophit (by time) in each channel |
| 24 | + if (risemap.find(ch) != risemap.end()) |
| 25 | + { |
| 26 | + if (tr < risemap[ch]) |
| 27 | + { |
| 28 | + risemap[ch] = ts + tr; |
| 29 | + } |
| 30 | + } |
| 31 | + else |
| 32 | + { |
| 33 | + risemap[ch] = ts + tr; |
| 34 | + } |
| 35 | +} |
| 36 | +// ----------------------------------------------------------------------------- |
| 37 | +int sbn::timing::getSideByChannel(const int channel) |
| 38 | +{ |
| 39 | + /* |
| 40 | + Channels are numbered from east to west, from North (cryo side) to South (beam side) |
| 41 | + We look in the opposide direction wrt to the beam direction South->North: |
| 42 | + - Left is the east wall of each cryostat; |
| 43 | + - Right is the west side of each cryostat; |
| 44 | + - [ 0:89 ] and [180:269] are on the left, |
| 45 | + the return value of the function is 0; |
| 46 | + - [ 90-179 ] and [ 270:359 ] are on the right, |
| 47 | + the return value of the function is 1; |
| 48 | + */ |
| 49 | + |
| 50 | + int side = channel / 90; // always round down |
| 51 | + return side % 2; |
| 52 | +} |
| 53 | + |
| 54 | +// ----------------------------------------------------------------------------- |
| 55 | +double sbn::timing::getFlashBunchTime(std::map<int, double> risemap, |
| 56 | + std::vector<sbn::timing::PMTBeamSignal> RWMTimes) |
| 57 | +{ |
| 58 | + // if no RWM info available, all pmt_start_time_rwm are invalid |
| 59 | + // return icarus::timing::NoTime as well for the flash |
| 60 | + if (RWMTimes.empty()) |
| 61 | + return sbn::timing::NoTime; |
| 62 | + |
| 63 | + std::vector<int> channels; |
| 64 | + std::vector<double> hit_rise_time_rwm; |
| 65 | + for (auto it = risemap.begin(); it != risemap.end(); it++){ |
| 66 | + int ch = it->first; |
| 67 | + channels.push_back(ch); |
| 68 | + auto rwm = RWMTimes.at(ch); |
| 69 | + if (!rwm.isValid()){ |
| 70 | + mf::LogTrace("PMTBeamSignal getFlashBunchTime") << "No RWM signal for channel " << ch << " " |
| 71 | + << "(Crate " << rwm.crate << ", Board " << rwm.digitizerLabel |
| 72 | + << ", SpecialChannel " << rwm.specialChannel << ")\n"; |
| 73 | + } |
| 74 | + float rwm_trigger = rwm.startTime; // rwm time w.r.t. trigger time [us] |
| 75 | + float firstHitRisetime_trigger = it->second; // first opHit rise time w.r.t. trigger time [us] |
| 76 | + hit_rise_time_rwm.push_back(firstHitRisetime_trigger - rwm_trigger); |
| 77 | + } |
| 78 | + |
| 79 | + double tfirst_left = std::numeric_limits<double>::max(); |
| 80 | + double tfirst_right = std::numeric_limits<double>::max(); |
| 81 | + |
| 82 | + int nleft = 0; |
| 83 | + int nright = 0; |
| 84 | + for(std::size_t i = 0; i < hit_rise_time_rwm.size(); i++){ |
| 85 | + int ch = channels[i]; |
| 86 | + int side = sbn::timing::getSideByChannel(ch); |
| 87 | + double t = hit_rise_time_rwm[i]; // rise time w.r.t. rwm |
| 88 | + |
| 89 | + // if any RWM copy is missing (therefore missing for an entire PMT crate), |
| 90 | + // it might not be possible to use the first hits (they might not have a RMW time) |
| 91 | + // so return icarus::timing::NoTime as in other bad cases |
| 92 | + if (!RWMTimes[i].isValid()) |
| 93 | + return sbn::timing::NoTime; |
| 94 | + |
| 95 | + // count hits separetely on the two walls |
| 96 | + if (side == 0) |
| 97 | + { |
| 98 | + nleft++; |
| 99 | + if (t < tfirst_left) |
| 100 | + tfirst_left = t; |
| 101 | + } |
| 102 | + else if (side == 1) |
| 103 | + { |
| 104 | + nright++; |
| 105 | + if (t < tfirst_right) |
| 106 | + tfirst_right = t; |
| 107 | + } |
| 108 | + } //end loop over m_hit_rise_time_rwm vector |
| 109 | + |
| 110 | + // if there are no hits in one of the walls... very rare? |
| 111 | + if (nleft < 1 || nright < 1) |
| 112 | + { |
| 113 | + mf::LogWarning("PMTBeamSignal getFlashBunchTime") << "Flash doesn't have hits on both walls!" |
| 114 | + << "Left: " << nleft << " t " << tfirst_left << " " |
| 115 | + << "Right: " << nright << " t " << tfirst_right; |
| 116 | + // return what we have... |
| 117 | + return (tfirst_left < tfirst_right) ? tfirst_left : tfirst_right; |
| 118 | + } |
| 119 | + |
| 120 | + return (tfirst_left + tfirst_right) / 2.; |
| 121 | + |
| 122 | +} |
0 commit comments