SND@LHC Software
Loading...
Searching...
No Matches
DriftTubeUnpack.cxx
Go to the documentation of this file.
1#include <cassert>
2#include <unordered_map>
3#include <bitset>
4#include <algorithm>
5#include <set>
6#include <tuple>
7
8// ROOT headers
9#include "ROOT/TSeq.hxx"
10#include "ROOT/RVec.hxx"
11
12// Fair headers
13#include "FairRootManager.h"
14#include "FairRunOnline.h"
15#include "FairLogger.h"
16
17// SHiP headers
18#include "DriftTubeUnpack.h"
19#include "MufluxSpectrometerHit.h"
20#include "ScintillatorHit.h"
22
24
25// DriftTubeUnpack: Constructor
27
28DriftTubeUnpack::DriftTubeUnpack(bool charm) : fCharm(charm) {}
29
30// Virtual DriftTubeUnpack: Public method
32
33// Init: Public method
35{
36 LOG(INFO) << "DriftTubeUnpack : Initialising in " << (fCharm ? "charm" : "muon flux") << " mode.";
37 Register();
38 return kTRUE;
39}
40
41// Register: Protected method
43{
44 LOG(INFO) << "DriftTubeUnpack : Registering..." ;
45 auto fMan = FairRootManager::Instance();
46 if (!fMan) {
47 return;
48 }
49 fMan->Register("Digi_MufluxSpectrometerHits", "DriftTubes", fRawTubes.get(), kTRUE);
50 fMan->Register("Digi_LateMufluxSpectrometerHits", "DriftTubes", fRawLateTubes.get(), kTRUE);
51 if (!fCharm) {
52 // Scintillator was removed for charm
53 fMan->Register("Digi_Scintillators", "DriftTubes", fRawScintillator.get(), kTRUE);
54 }
55 fMan->Register("Digi_BeamCounters", "DriftTubes", fRawBeamCounter.get(), kTRUE);
56 fMan->Register("Digi_MasterTrigger", "DriftTubes", fRawMasterTrigger.get(), kTRUE);
57 fMan->Register("Digi_Triggers", "DriftTubes", fRawTriggers.get(), kTRUE);
58}
59
60// DoUnpack: Public method
61Bool_t DriftTubeUnpack::DoUnpack(Int_t *data, Int_t size)
62{
63 LOG(DEBUG) << "DriftTubeUnpack : Unpacking frame... size/bytes = " << size ;
64
65 auto df = reinterpret_cast<DataFrame *>(data);
66 assert(df->header.size == size);
67 switch (df->header.frameTime) {
68 case SoS: LOG(DEBUG) << "DriftTubeUnpacker: SoS frame." ; return kTRUE;
69 case EoS: LOG(DEBUG) << "DriftTubeUnpacker: EoS frame." ; return kTRUE;
70 default: break;
71 }
72 LOG(DEBUG) << "Sequential trigger number " << df->header.timeExtent ;
73 auto nhits = df->getHitCount();
74 int nhitsTubes = 0;
75 int nhitsLateTubes = 0;
76 int nhitsScintillator = 0;
77 int nhitsBeamCounter = 0;
78 int nhitsMasterTrigger = 0;
79 int nhitsTriggers = 0;
80 auto flags = df->header.flags;
81 int trigger = 0;
82 int expected_triggers = 5;
83 if ((flags & DriftTubes::All_OK) == DriftTubes::All_OK) {
84 LOG(DEBUG) << "All TDCs are OK" ;
85 } else {
86 LOG(DEBUG) << "Not all TDCs are OK:" << std::bitset<16>(flags) ;
87 for (auto i : ROOT::MakeSeq(5)) {
88 if ((flags & 1 << (i + 1)) == 1 << (i + 1)) {
89 expected_triggers--;
90 LOG(WARNING) << "TDC " << i << " NOT OK" ;
91 } else {
92 LOG(DEBUG) << "TDC " << i << " OK" ;
93 }
94 }
95 }
96 ROOT::VecOps::RVec<RawDataHit> hits(df->hits, df->hits + nhits);
97 ROOT::VecOps::RVec<RawDataHit> leading, trailing;
98 int n_matched = 0;
99 int n_unmatched = 0;
100 std::set<uint16_t> channels;
101 for (auto &&hit : hits) {
102 channels.emplace(hit.channelId % 0x1000);
103 (hit.channelId < 0x1000 ? leading : trailing).emplace_back(hit);
104 }
105 assert(leading.size() + trailing.size() == hits.size());
106 LOG(DEBUG) << leading.size() << '\t' << trailing.size() << '\t' << hits.size();
107 const int n_leading = leading.size();
108 auto compare_hit_time = [](const RawDataHit &a, const RawDataHit &b) { return a.hitTime < b.hitTime; };
109 std::sort(leading.begin(), leading.end(), compare_hit_time);
110 std::sort(trailing.begin(), trailing.end(), compare_hit_time);
111 std::unordered_map<uint16_t, ROOT::VecOps::RVec<RawDataHit>> channel_leading;
112 for (auto &&hit : leading) {
113 assert(hit.channelId < 0x1000);
114 channel_leading[hit.channelId % 0x1000].emplace_back(hit);
115 }
116 std::unordered_map<uint16_t, ROOT::VecOps::RVec<RawDataHit>> channel_trailing;
117 for (auto &&hit : trailing) {
118 assert(hit.channelId >= 0x1000);
119 channel_trailing[hit.channelId % 0x1000].emplace_back(hit);
120 }
121 ROOT::VecOps::RVec<std::tuple<uint16_t, uint16_t, Float_t, bool, bool>> matches;
122 for (auto &&channel : channels) {
123 bool first = true;
124 LOG(DEBUG) << "Channel: " << channel;
125 assert(channel < 0x1000);
126 auto leading_hits = channel_leading[channel];
127 auto trailing_hits = channel_trailing[channel];
128 auto difference = int(leading_hits.size() - trailing_hits.size());
129 if (difference != 0) {
130 LOG(DEBUG) << "Difference between leading/trailing edges: " << difference;
131 }
132 for (int i = 0, j = 0; i < leading_hits.size(); i++) {
133 LOG(DEBUG) << "i=" << i << "\tj=" << j;
134 LOG(DEBUG) << "leading_hits.size()=" << leading_hits.size()
135 << "\ttrailing_hits.size()=" << trailing_hits.size();
136 assert(i < leading_hits.size());
137 if (j < trailing_hits.size() && leading_hits.at(i).hitTime < trailing_hits.at(j).hitTime &&
138 (i + 1 >= leading_hits.size() || trailing_hits.at(j).hitTime < leading_hits.at(i + 1).hitTime)) {
139 // Successful match
140 LOG(DEBUG) << "Successful match on channel " << channel;
141 uint16_t time = leading_hits.at(i).hitTime;
142 Float_t time_over_threshold = 0.098 * (trailing_hits.at(j).hitTime - leading_hits.at(i).hitTime);
143 matches.emplace_back(channel, time, time_over_threshold, first, true);
144 n_matched++;
145 first = false;
146 j++;
147 } else if (j < trailing_hits.size() && leading_hits.at(i).hitTime > trailing_hits.at(j).hitTime &&
148 (j + 1) < trailing_hits.size()) {
149 // No match for leading edge
150 // Try again with next j, same i
151 LOG(DEBUG) << "Try again for hit on channel " << channel;
152 i--;
153 j++;
154 } else {
155 LOG(DEBUG) << "No match found for hit on channel " << channel;
156 // No match possible, save unmatched hit
157 uint16_t time = leading_hits.at(i).hitTime;
158 Float_t time_over_threshold = 167.2; // Estimated from data
159 matches.emplace_back(channel, time, time_over_threshold, first, false);
160 first = false;
161 n_unmatched++;
162 }
163 }
164 }
165 assert(n_matched + n_unmatched == n_leading);
166 LOG(DEBUG) << "Successfully matched " << n_matched << "/" << n_leading << "(" << hits.size() << " hits)";
167
168 std::unordered_map<int, uint16_t> trigger_times;
169 ROOT::VecOps::RVec<std::tuple<uint16_t, uint16_t, Float_t, bool, uint16_t>> drifttube_hits;
170 uint16_t master_trigger_time = 0;
171 for (auto &&match : matches) {
172 uint16_t channel, hit_time;
173 Float_t time_over_threshold;
174 bool first, matched;
175 std::tie(channel, hit_time, time_over_threshold, first, matched) = match;
176 auto hit_flags = matched ? flags : flags | DriftTubes::NoWidth;
177 auto id = *(reinterpret_cast<ChannelId *>(&channel));
178 auto detectorId = fCharm ? id.GetDetectorIdCharm() : id.GetDetectorId();
179 auto TDC = id.TDC;
180 if (detectorId == 0) {
181 // Trigger
182 trigger++;
183 if (trigger_times.find(TDC) != trigger_times.end()) {
184 LOG(DEBUG) << "Found time " << trigger_times[TDC] << " for TDC " << TDC ;
185 trigger_times[TDC] = std::min(hit_time, trigger_times[TDC]);
186 } else {
187 LOG(DEBUG) << "Inserting new time " << hit_time ;
188 trigger_times[TDC] = hit_time;
189 }
190 LOG(DEBUG) << TDC << '\t' << hit_time << '\t' << trigger_times[TDC] ;
191 new ((*fRawTriggers)[nhitsTriggers])
192 ScintillatorHit(detectorId, 0.098 * Float_t(hit_time), time_over_threshold, hit_flags, channel);
193 nhitsTriggers++;
194 } else if (detectorId == -2) {
195 // Blacklisted channel
196 continue;
197 } else if (detectorId == 1) {
198 // Master trigger
199 //
200 // Use the earliest if there are several
201 if (nhitsMasterTrigger == 0 || hit_time < master_trigger_time) {
202 master_trigger_time = hit_time;
203 }
204 new ((*fRawMasterTrigger)[nhitsMasterTrigger])
205 ScintillatorHit(detectorId, 0.098 * Float_t(hit_time), time_over_threshold, hit_flags, channel);
206 nhitsMasterTrigger++;
207 } else if (detectorId == -1) {
208 // beam counter
209 new ((*fRawBeamCounter)[nhitsBeamCounter])
210 ScintillatorHit(detectorId, 0.098 * Float_t(hit_time), time_over_threshold, hit_flags, channel);
211 nhitsBeamCounter++;
212 } else if (detectorId == 6 || detectorId == 7) {
213 // trigger scintillator
214 if (fCharm) {
215 LOG(ERROR) << "Scintillator hit found! There should not be any in the charmxsec measurement!"
216 ;
217 }
218 continue;
219 new ((*fRawScintillator)[nhitsScintillator])
220 ScintillatorHit(detectorId, 0.098 * Float_t(hit_time), time_over_threshold, hit_flags, channel);
221 nhitsScintillator++;
222 } else {
223 drifttube_hits.emplace_back(channel, hit_time, time_over_threshold, first, hit_flags);
224 }
225 }
226
227 int32_t delay = 13500; // Best guess based on data
228 if (!trigger_times[4]) {
229 LOG(WARNING) << "No trigger in TDC 4, guessing delay" ;
230 flags |= DriftTubes::NoDelay;
231 } else if (master_trigger_time == 0) {
232 LOG(WARNING) << "No master trigger, guessing delay" ;
233 flags |= DriftTubes::NoDelay;
234 } else {
235 delay = trigger_times[4] - master_trigger_time;
236 LOG(DEBUG) << "Delay [ns]:";
237 LOG(DEBUG) << 0.098 * delay << " = " << 0.098 * trigger_times[4] << " - " << 0.098 * master_trigger_time;
238 }
239
240 for (auto &&hit : drifttube_hits) {
241 uint16_t channel, raw_time, hit_flags;
242 Float_t time_over_threshold;
243 bool first;
244 std::tie(channel, raw_time, time_over_threshold, first, hit_flags) = hit;
245 hit_flags |= flags;
246 auto id = *(reinterpret_cast<ChannelId *>(&channel));
247 auto detectorId = fCharm ? id.GetDetectorIdCharm() : id.GetDetectorId();
248 auto TDC = id.TDC;
249 Float_t time;
250 try {
251 auto trigger_time = trigger_times.at(TDC);
252 time = 0.098 * (delay - trigger_time + raw_time);
253 } catch (const std::out_of_range &e) {
254 LOG(WARNING) << e.what() << "\t TDC " << TDC << "\t Detector ID " << detectorId << "\t Channel " << channel
255 << "\t Sequential trigger number " << df->header.timeExtent ;
256 time = 0.098 * raw_time;
257 hit_flags |= DriftTubes::NoTrigger;
258 }
259 if (time > 4000) {
260 LOG(WARNING) << "Late event found with time [ns]:";
261 LOG(WARNING) << time << " = " << 0.098 * delay << " - " << 0.098 * (delay + raw_time) - time << " - "
262 << 0.098 * raw_time;
263 }
264
265 new ((*(first ? fRawTubes : fRawLateTubes))[first ? nhitsTubes : nhitsLateTubes])
266 MufluxSpectrometerHit(detectorId, time, time_over_threshold, hit_flags, channel);
267 (first ? nhitsTubes : nhitsLateTubes)++;
268 }
269
270 if (trigger < expected_triggers) {
271 LOG(INFO) << trigger << " triggers." ;
272 } else {
273 LOG(DEBUG) << trigger << " triggers." ;
274 }
275
276 return kTRUE;
277}
278
279// Reset: Public method
281{
282 LOG(DEBUG) << "DriftTubeUnpack : Clearing Data Structure" ;
283 fRawTubes->Clear();
284 fRawLateTubes->Clear();
285 fRawScintillator->Clear();
286 fRawBeamCounter->Clear();
287 fRawMasterTrigger->Clear();
288 fRawTriggers->Clear();
289}
290
std::unique_ptr< TClonesArray > fRawMasterTrigger
std::unique_ptr< TClonesArray > fRawBeamCounter
virtual Bool_t Init() override
virtual Bool_t DoUnpack(Int_t *data, Int_t size) override
virtual void Register() override
std::unique_ptr< TClonesArray > fRawTriggers
std::unique_ptr< TClonesArray > fRawTubes
virtual ~DriftTubeUnpack()
std::unique_ptr< TClonesArray > fRawLateTubes
virtual void Reset() override
std::unique_ptr< TClonesArray > fRawScintillator
ClassImp(ecalContFact) ecalContFact