ATLAS Offline Software
Loading...
Searching...
No Matches
PadEmulatorTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "PadEmulatorTool.h"
6
7namespace NSWL1 {
8 PadEmulatorTool::PadEmulatorTool(const std::string& type, const std::string& name, const IInterface* parent) :
9 base_class(type,name,parent) {}
10
12 ATH_MSG_INFO( m_isMC.name() << " --> " << (m_isMC ? "[True]" : "[False]")
13 << ", " << m_doNtuple.name() << " --> " << (m_doNtuple ? "[True]" : "[False]")
14 << ", " << m_stretch.name() << " --> " << m_stretch.value()
15 << ", " << m_ignoreBCIDs.name() << " --> " << (m_ignoreBCIDs ? "[True]" : "[False]")
16 << ", " << m_lastPhiOnly.name() << " --> " << (m_lastPhiOnly ? "[True]" : "[False]")
17 << ", " << m_bandIDPriorityEncode.name() << " --> " << (m_bandIDPriorityEncode ? "[True]" : "[False]")
18 << ", " << m_noDuplicates.name() << " --> " << (m_noDuplicates ? "[True]" : "[False]")
19 << ", " << m_triggerLogic.name() << " --> " << m_triggerLogic.value()
20 << ", " << m_pattername_L.name() << " --> " << m_pattername_L.value()
21 << ", " << m_pattername_S.name() << " --> " << m_pattername_S.value() );
22
23 ATH_CHECK(m_idHelperSvc.retrieve());
24 ATH_CHECK(m_detectorManagerKey.initialize());
26 ATH_CHECK(m_dcsKey.initialize(!m_isMC));
27
28 // Read pattern file for large and small sectors
31
32 // Mask specific patterns according to known issues
34
35 // Create ROB IDs
37
38 // Do not allow debug ntuple in multi-threaded mode
39 if(m_doNtuple and Gaudi::Concurrency::ConcurrencyFlags::numConcurrentEvents() > 1) {
40 ATH_MSG_ERROR("DoNtuple is not possible in multi-threaded mode");
41 return StatusCode::FAILURE;
42 }
43
44 ATH_MSG_DEBUG("Successfully initialized " << name() );
45 return StatusCode::SUCCESS;
46 }
47
49 m_padTrigger_digits_sector = std::make_shared<MuonVal::VectorBranch<int> >(tree, "sTGC_PadTrigger_digits_sector");
50 m_padTrigger_digits_eta = std::make_shared<MuonVal::VectorBranch<int> >(tree, "sTGC_PadTrigger_digits_eta");
51 m_padTrigger_digits_phi = std::make_shared<MuonVal::VectorBranch<int> >(tree, "sTGC_PadTrigger_digits_phi");
52 m_padTrigger_digits_multilayer = std::make_shared<MuonVal::VectorBranch<int> >(tree, "sTGC_PadTrigger_digits_multilayer");
53 m_padTrigger_digits_gasgap = std::make_shared<MuonVal::VectorBranch<int> >(tree, "sTGC_PadTrigger_digits_gasgap");
54 m_padTrigger_digits_source_id = std::make_shared<MuonVal::VectorBranch<uint32_t> >(tree, "sTGC_PadTrigger_digits_source_id");
55 m_padTrigger_digits_pfeb = std::make_shared<MuonVal::VectorBranch<uint32_t> >(tree, "sTGC_PadTrigger_digits_pfeb");
56 m_padTrigger_digits_pad_channel = std::make_shared<MuonVal::VectorBranch<uint32_t> >(tree, "sTGC_PadTrigger_digits_padchannel");
57 m_padTrigger_digits_relbcid = std::make_shared<MuonVal::VectorBranch<uint32_t> >(tree, "sTGC_PadTrigger_digits_relbcid");
58 m_padTrigger_TP_R_id_init = std::make_shared<MuonVal::VectorBranch<uint8_t> >(tree, "sTGC_PadTrigger_TP_R_id_init");
59 m_padTrigger_TP_phi_id_init = std::make_shared<MuonVal::VectorBranch<uint8_t> >(tree, "sTGC_PadTrigger_TP_phi_id_init");
60 m_padTrigger_TP_relbcid_init = std::make_shared<MuonVal::VectorBranch<uint32_t> >(tree, "sTGC_PadTrigger_TP_relbcid_init");
61 m_padTrigger_TP_R_id = std::make_shared<MuonVal::VectorBranch<uint8_t> >(tree, "sTGC_PadTrigger_TP_R_id");
62 m_padTrigger_TP_phi_id = std::make_shared<MuonVal::VectorBranch<uint8_t> >(tree, "sTGC_PadTrigger_TP_phi_id");
63 m_padTrigger_TP_relbcid = std::make_shared<MuonVal::VectorBranch<uint32_t> >(tree, "sTGC_PadTrigger_TP_relbcid");
64 m_padTrigger_wheel = std::make_shared<MuonVal::VectorBranch<char> >(tree, "sTGC_PadTrigger_wheel");
65 m_padTrigger_sector = std::make_shared<MuonVal::VectorBranch<uint32_t> >(tree, "sTGC_PadTrigger_sector");
66 m_padTrigger_hitmask = std::make_shared<MuonVal::VectorBranch<uint32_t> >(tree, "sTGC_PadTrigger_hitmask");
67 m_padTrigger_efficiency = std::make_shared<MuonVal::VectorBranch<uint32_t> >(tree, "sTGC_PadTrigger_efficiency");
68
69 tree.addBranch(m_padTrigger_digits_sector);
70 tree.addBranch(m_padTrigger_digits_eta);
71 tree.addBranch(m_padTrigger_digits_phi);
72 tree.addBranch(m_padTrigger_digits_multilayer);
73 tree.addBranch(m_padTrigger_digits_gasgap);
74 tree.addBranch(m_padTrigger_digits_source_id);
75 tree.addBranch(m_padTrigger_digits_pfeb);
76 tree.addBranch(m_padTrigger_digits_pad_channel);
77 tree.addBranch(m_padTrigger_digits_relbcid);
78 tree.addBranch(m_padTrigger_TP_R_id_init);
79 tree.addBranch(m_padTrigger_TP_phi_id_init);
80 tree.addBranch(m_padTrigger_TP_relbcid_init);
81 tree.addBranch(m_padTrigger_TP_R_id);
82 tree.addBranch(m_padTrigger_TP_phi_id);
83 tree.addBranch(m_padTrigger_TP_relbcid);
84 tree.addBranch(m_padTrigger_wheel);
85 tree.addBranch(m_padTrigger_sector);
86 tree.addBranch(m_padTrigger_hitmask);
87 tree.addBranch(m_padTrigger_efficiency);
88
89 return StatusCode::SUCCESS;
90 }
91
92 /*
93 ***** Main algorithm tool
94 */
95 StatusCode PadEmulatorTool::emulate(const EventContext& ctx, Muon::NSW_PadTriggerDataContainer *out) const {
96
98 if(!detManager.isValid()){
99 ATH_MSG_ERROR("Failed to retrieve the MuonDetectorManager conditions object");
100 return StatusCode::FAILURE;
101 }
102
104 if(!sTGCdigits.isValid()) {
105 ATH_MSG_ERROR("Failed to retrieve the sTGC Digit container");
106 return StatusCode::FAILURE;
107 }
108
109 const NswDcsDbData* dcsData = nullptr;
110 if(!m_isMC) {
111 SG::ReadCondHandle<NswDcsDbData> dcsDataHandle{m_dcsKey, ctx};
112 if(!dcsDataHandle.isValid()) {
113 ATH_MSG_ERROR("Failed to retrieve DCS data while running on data");
114 return StatusCode::FAILURE;
115 }
116 dcsData = dcsDataHandle.cptr();
117 }
118
119 const std::array<uint16_t, 8> bcWindow = {0, 1, 2, 3, 4, UINT16_MAX-1, UINT16_MAX-2, UINT16_MAX-3};
120 for(const sTgcDigitCollection* digitCollection : *sTGCdigits) {
121
122 std::vector<uint32_t> hits_sourceid{}, hits_pfeb{}, hits_padchan{}, hits_relbcid{};
123 for(const sTgcDigit* digit : *digitCollection) {
124 if(m_idHelperSvc->stgcIdHelper().channelType(digit->identify()) == sTgcIdHelper::sTgcChannelTypes::Pad) {
125 if(std::find(bcWindow.begin(), bcWindow.end(), digit->bcTag()) != bcWindow.end()) {
126 const Identifier Id = digit->identify();
127 if(!m_isMC) {
128 if(!dcsData->isConnectedChannel(Id) or !dcsData->isGood(ctx, Id) or !dcsData->isGoodHv(Id) or !dcsData->isGoodEltx(Id)) continue;
129 bool disabled = false;
130 if(!dcsData->isGoodTDaq(ctx,Id,disabled)) continue;
131 }
132
133 const int stEta = m_idHelperSvc->stationEta(Id);
134 const int stPhi = m_idHelperSvc->stationPhi(Id);
135 const int multilayer = m_idHelperSvc->stgcIdHelper().multilayer(Id);
136 const int gasGap = m_idHelperSvc->stgcIdHelper().gasGap(Id);
137 const int channel = m_idHelperSvc->stgcIdHelper().channel(Id);
138 ATH_MSG_DEBUG("Digit: " << m_idHelperSvc->toString(Id) << " - BC: " << digit->bcTag());
139
140 // Source ID retrieval: Pad Trigger logic needs sector number starting from 0
141 int sector = m_idHelperSvc->sector(Id)-1;
142 const char wheel = (stEta > 0) ? 'A' : 'C';
143 auto sourceid = NSWL1::PAD::wheelSectorToSourceID(wheel, sector);
144 hits_sourceid.emplace_back(sourceid);
145
146 // pFEB retrieval
147 auto pfeb = NSWL1::PAD::getpFEBAthena(gasGap, multilayer, stEta);
148 hits_pfeb.emplace_back(pfeb);
149
150 // padChannel retrieval: no check on the Type, as already done by selecting PAD digits only
151 auto padchan = NSWL1::PAD::getPadchAthena(channel, pfeb, sector, gasGap);
152 hits_padchan.emplace_back(padchan);
153
154 // BC retrieval
155 hits_relbcid.emplace_back(digit->bcTag());
156
157 if(m_doNtuple) {
158 m_padTrigger_digits_sector->push_back(sector);
159 m_padTrigger_digits_eta->push_back(stEta);
160 m_padTrigger_digits_phi->push_back(stPhi);
161 m_padTrigger_digits_multilayer->push_back(multilayer);
162 m_padTrigger_digits_gasgap->push_back(gasGap);
163 m_padTrigger_digits_source_id->push_back(sourceid);
164 m_padTrigger_digits_pfeb->push_back(pfeb);
165 m_padTrigger_digits_pad_channel->push_back(padchan);
166 m_padTrigger_digits_relbcid->push_back(digit->bcTag());
167 }
168 }
169 }
170 }
171 ATH_MSG_DEBUG("Processed sTGC digit collection with size " << digitCollection->size() << ", finding a total of " << hits_sourceid.size() << " pad hits");
172
173 for(const auto &rob : m_robIDs) {
174 if(hits_sourceid.empty() or hits_pfeb.empty() or hits_padchan.empty() or hits_relbcid.empty()) continue;
175
176 // Find robID
177 std::vector<uint32_t> hits_indices{};
178 for(size_t index{0}; index < hits_sourceid.size(); ++index) {
179 if(hits_sourceid.at(index) == rob) hits_indices.emplace_back(index);
180 }
181
182 if(hits_indices.empty()) continue;
183
184 // Preprocessing
185 const auto& sourceid = hits_sourceid.at(hits_indices.front());
186 const bool isLarge = (sourceid % 2 == 0);
187 const bool isA = NSWL1::isA(sourceid);
188 const char whl = isA ? 'A' : 'C';
189 const auto sec = (sourceid & 0xf); // last 4 bits of the sourceID are sector number (0-15)
190 const auto& patterns = isLarge ? m_patterns_L : m_patterns_S;
191 std::vector<uint32_t> masks(patterns.size() * NSWL1::PAD::PAD_TRIGGER_READOUT_NBC);
192
193 // Loop over available hits
194 for(const auto& index: hits_indices) {
195 const auto& pfeb = hits_pfeb.at(index);
196 const auto& chan = hits_padchan.at(index);
197 const auto& bcid = m_ignoreBCIDs ? 0 : hits_relbcid.at(index);
198 ATH_MSG_DEBUG("PadTrigger sector " << whl << sec+1 << std::dec << " -> Hit " << index << " pfeb " << pfeb << " padchan " << chan << " bcid " << bcid);
199
200 /* What we are getting here:
201 * producing a vector with size # of patterns * number of bunch crossings
202 * so we have pattern A BCID 0, pattern B BCID 0,..., pattern A BCID 1, pattern B BCID 1
203 * pattern A BCID 0 = 00000000 if no layers were hit, 00010101 if layers 0, 2, and 4 were hit
204 * for each hit, find the patterns it belongs to
205 * then for the corresponding bcid and the ones within stretch, mark the layer as hit
206 */
207 const auto layer = (pfeb % NSWL1::PAD::NPFEB_PER_RADIUS);
208 for(size_t it{0}; it < patterns.size(); ++it) {
209 if(patterns.at(it).getPfebs().at(layer) == pfeb and patterns.at(it).getPadChannels().at(layer) == chan) {
210 for(uint32_t bc{bcid}; bc <= bcid + m_stretch; ++bc) {
212 masks.at(it + bc*patterns.size()) |= (1 << layer);
213 }
214 }
215 }
216 }
217
218 // Checking for problems/transitionregions/pads that are masked to 1
219 std::string secstr = whl + std::to_string(sec+1);
220 if(m_maskedPatterns.find(secstr) != m_maskedPatterns.end()) {
221 for(const auto& [patind, tomask] : m_maskedPatterns.at(secstr)) {
222 for(size_t bcid{0}; bcid < NSWL1::PAD::PAD_TRIGGER_READOUT_NBC; ++bcid) {
223 masks.at(patind + bcid*patterns.size()) |= tomask;
224 }
225 }
226 }
227
228 // Check coincidences
229 for(size_t relbcid{0}; relbcid < NSWL1::PAD::PAD_TRIGGER_READOUT_NBC; ++relbcid) {
230 if(m_ignoreBCIDs and relbcid > 0) continue;
231
232 bool isTrigger;
233 std::vector<PadEmulatorTrigger> triggersBc{};
234 for (size_t it{0}; it < patterns.size(); ++it) {
235 const auto& pattern = patterns.at(it);
236 const uint32_t hitmask = masks.at(it + relbcid*patterns.size());
237 if(m_triggerLogic == "4over8") {
238 isTrigger = trigger_4over8(hitmask & 0x01, hitmask & 0x02, hitmask & 0x04, hitmask & 0x08,
239 hitmask & 0x10, hitmask & 0x20, hitmask & 0x40, hitmask & 0x80);
240 }
241 else if(m_triggerLogic == "3and1") {
242 isTrigger = trigger_3and1(hitmask & 0x01, hitmask & 0x02, hitmask & 0x04, hitmask & 0x08,
243 hitmask & 0x10, hitmask & 0x20, hitmask & 0x40, hitmask & 0x80);
244 }
245 else if(m_triggerLogic == "2and2") {
246 isTrigger = trigger_2and2(hitmask & 0x01, hitmask & 0x02, hitmask & 0x04, hitmask & 0x08,
247 hitmask & 0x10, hitmask & 0x20, hitmask & 0x40, hitmask & 0x80);
248 }
249 else if(m_triggerLogic == "specific4over8") {
250 isTrigger = trigger_specific4over8(hitmask & 0x01, hitmask & 0x02, hitmask & 0x04, hitmask & 0x08,
251 hitmask & 0x10, hitmask & 0x20, hitmask & 0x40, hitmask & 0x80);
252 }
253 else if(m_triggerLogic == "5over8") {
254 isTrigger = trigger_5over8(hitmask & 0x01, hitmask & 0x02, hitmask & 0x04, hitmask & 0x08,
255 hitmask & 0x10, hitmask & 0x20, hitmask & 0x40, hitmask & 0x80);
256 }
257 else if(m_triggerLogic == "specific5over8") {
258 isTrigger = trigger_specific5over8(hitmask & 0x01, hitmask & 0x02, hitmask & 0x04, hitmask & 0x08,
259 hitmask & 0x10, hitmask & 0x20, hitmask & 0x40, hitmask & 0x80);
260 }
261 else if(m_triggerLogic == "superspecific5over8") {
262 isTrigger = trigger_superspecific5over8(hitmask & 0x01, hitmask & 0x02, hitmask & 0x04, hitmask & 0x08,
263 hitmask & 0x10, hitmask & 0x20, hitmask & 0x40, hitmask & 0x80);
264 }
265 else if(m_triggerLogic == "2x3over4") {
266 isTrigger = trigger_2X_3over4(hitmask & 0x01, hitmask & 0x02, hitmask & 0x04, hitmask & 0x08,
267 hitmask & 0x10, hitmask & 0x20, hitmask & 0x40, hitmask & 0x80);
268 }
269 else if(m_triggerLogic == "6over8") {
270 isTrigger = trigger_6over8(hitmask & 0x01, hitmask & 0x02, hitmask & 0x04, hitmask & 0x08,
271 hitmask & 0x10, hitmask & 0x20, hitmask & 0x40, hitmask & 0x80);
272 }
273 else if(m_triggerLogic == "8over8") {
274 isTrigger = trigger_8over8(hitmask & 0x01, hitmask & 0x02, hitmask & 0x04, hitmask & 0x08,
275 hitmask & 0x10, hitmask & 0x20, hitmask & 0x40, hitmask & 0x80);
276 }
277 else {
278 ATH_MSG_ERROR("Unknown sTGC Pad Trigger logic!");
279 return StatusCode::FAILURE;
280 }
281 if(not isTrigger) continue;
282
283 // Save the output
284 triggersBc.emplace_back(
285 PadEmulatorTrigger(whl, sec, pattern.getBandid(), pattern.getPhiid(isA), relbcid, pattern, hitmask)
286 );
287 } // Closing loop on patterns
288 if(m_doNtuple) {
289 m_padTrigger_efficiency->push_back(triggersBc.size());
290 for(const auto& trigger : triggersBc) {
291 if(relbcid != trigger.getRelbcid()) continue;
292 m_padTrigger_TP_R_id_init->push_back(trigger.getBandid());
293 m_padTrigger_TP_phi_id_init->push_back(trigger.getPhiid());
294 m_padTrigger_TP_relbcid_init->push_back(trigger.getRelbcid());
295 }
296 }
297
298 // Filter output: eta bias
299 triggersBc = (m_bandIDPriorityEncode) ? filterPriorityEncoder(triggersBc, isLarge) : filterLowBandIDs(triggersBc);
300 if(m_doNtuple) m_padTrigger_efficiency->push_back(triggersBc.size());
301
302 // Filter output: phi bias
303 if(m_lastPhiOnly) triggersBc = filterLastPhiOnly(triggersBc);
304 if(m_doNtuple) m_padTrigger_efficiency->push_back(triggersBc.size());
305
306 // Filter output: duplicates of triggers with the same band and phi IDs in the same BC
307 if(m_noDuplicates) triggersBc = filterDuplicates(triggersBc);
308 if(m_doNtuple) m_padTrigger_efficiency->push_back(triggersBc.size());
309
310 // Save the filtered output in the final container, for coincidence checks in the SL
311 if(not triggersBc.empty()) {
312 auto newCollection = new Muon::NSW_PadTriggerData(isA, sec, relbcid, 0);
313 for(const auto& trigger : triggersBc) {
314 if(relbcid != trigger.getRelbcid()) continue;
315 newCollection->addTrigger(trigger.getBandid(), trigger.getPhiid(), 0);
316 if(m_doNtuple) {
317 m_padTrigger_TP_R_id->push_back(trigger.getBandid());
318 m_padTrigger_TP_phi_id->push_back(trigger.getPhiid());
319 m_padTrigger_TP_relbcid->push_back(trigger.getRelbcid());
320 m_padTrigger_wheel->push_back(trigger.getWheel());
321 m_padTrigger_sector->push_back(trigger.getSector());
322 m_padTrigger_hitmask->push_back(trigger.getHitMask());
323 }
324 }
325 if(out->addCollection(newCollection, out->numberOfCollections()).isFailure()) {
326 ATH_MSG_ERROR("Failed while storing output in the Muon::NSW_PadTriggerDataContainer");
327 return StatusCode::FAILURE;
328 }
329 }
330 } // Closing loop on relative BCIDs
331 } // Closing loop on ROBs
332 } // Closing loop on digit collections
333 return StatusCode::SUCCESS;
334 }
335
336 /*
337 ***** Filter functions below:
338 *** Retrieval of forbidden bandIDs
339 *** Take into account eta bias
340 *** Take into account phi bias
341 *** Remove duplicates of triggers with the same band and phi IDs in the same BC
342 */
343 std::vector<uint32_t> PadEmulatorTool::getForbiddenBandIDs(const std::vector<PadEmulatorTrigger>& triggers,
344 const bool isLarge) const {
345 std::set<uint32_t> forbiddens{};
346 const auto& encoder = isLarge ? NSWL1::PAD::priorityEncoderL : NSWL1::PAD::priorityEncoderS;
347
348 std::set<uint32_t> bands{};
349 for(const auto& trigger : triggers) bands.emplace(trigger.getBandid());
350 auto bandids = std::vector<uint32_t>(bands.cbegin(), bands.cend());
351
352 std::sort(bandids.rbegin(), bandids.rend());
353 for(const auto& bandid : bandids) {
354 if(NSWL1::PAD::contains(forbiddens, bandid)) continue;
355
356 for(uint32_t forb{bandid-1}; forb >= encoder(bandid); --forb) forbiddens.emplace(forb);
357 }
358
359 // bandid less than 6 is forbidden
360 for(const auto& bandid : {0, 1, 2, 3, 4, 5}) forbiddens.emplace(bandid);
361
362 return std::vector<uint32_t>(forbiddens.cbegin(), forbiddens.cend());
363 }
364
365 std::vector<PadEmulatorTrigger> PadEmulatorTool::filterPriorityEncoder(const std::vector<PadEmulatorTrigger>& input,
366 const bool isLarge) const {
367 if(input.empty()) return {};
368
369 std::vector<PadEmulatorTrigger> output{};
370 const auto& forbiddens = getForbiddenBandIDs(input, isLarge);
371 for(const auto& trigger: input) {
372 if(NSWL1::PAD::contains(forbiddens, trigger.getBandid())) continue;
373 output.emplace_back(trigger);
374 }
375 return output;
376 }
377
378 std::vector<PadEmulatorTrigger> PadEmulatorTool::filterLowBandIDs(const std::vector<PadEmulatorTrigger>& input) const {
379 if(input.empty()) return {};
380
381 std::vector<PadEmulatorTrigger> output{};
382 const std::set<uint32_t> forbiddens{0, 1, 2, 3, 4, 5};
383 for(const auto& trigger : input) {
384 if(NSWL1::PAD::contains(forbiddens, trigger.getBandid())) continue;
385 output.emplace_back(trigger);
386 }
387 return output;
388 }
389
390 std::vector<PadEmulatorTrigger> PadEmulatorTool::filterLastPhiOnly(const std::vector<PadEmulatorTrigger>& input) const {
391 if(input.empty()) return {};
392
393 std::map<uint32_t, std::vector<uint32_t> > phisPerBand{};
394 for(const auto& trigger : input) {
395 phisPerBand.try_emplace(trigger.getBandid(), std::vector<uint32_t>());
396 phisPerBand.at(trigger.getBandid()).emplace_back(trigger.getPhiid());
397 }
398
399 std::vector<PadEmulatorTrigger> output{};
400 for(const auto& trigger : input) {
401 if(trigger.getPhiid() != phisPerBand.at(trigger.getBandid()).back()) continue;
402 output.emplace_back(trigger);
403 }
404 return output;
405 }
406
407 std::vector<PadEmulatorTrigger> PadEmulatorTool::filterDuplicates(const std::vector<PadEmulatorTrigger>& input) const {
408 if(input.empty()) return {};
409
410 std::vector<PadEmulatorTrigger> output{};
411 for(const auto& trigger : input) {
412 if(std::any_of(output.cbegin(), output.cend(), [&](const auto& cmp) {
413 return trigger.getBandid() == cmp.getBandid() and trigger.getPhiid() == cmp.getPhiid();
414 })) continue;
415 output.emplace_back(trigger);
416 }
417 return output;
418 }
419
420 /*
421 ***** Load patterns when initializing the algorithm tool
422 */
423 StatusCode PadEmulatorTool::loadPatterns(const std::string& pfile) {
424 if(pfile.empty()) {
425 ATH_MSG_ERROR("Empty filename string for pad pattern file. No pattern will be loaded");
426 return StatusCode::FAILURE;
427 }
428
429 std::ifstream ifs(pfile);
430 std::string line;
431 if(ifs) {
432 bool isLarge = false;
433 uint32_t bandid = NSWL1::PAD::DUMMY_BANDID;
434 while (not ifs.eof()) {
435 std::getline(ifs, line);
436 const auto words = CxxUtils::tokenize(line, NSWL1::SPACE);
437 ATH_MSG_DEBUG("Got words of size " << words.size());
438
439 // check for EOF line
441 ATH_MSG_DEBUG("Not pattern end line ");
442
443 // find the current bandID
446 bandid = NSWL1::PAD::parseLineForBandid(line);
447 continue;
448 }
449 ATH_MSG_DEBUG("Parsed line for band ID " << bandid << " for large sector " << isLarge);
450
451 // skip uninteresting lines
452 if(bandid == NSWL1::PAD::DUMMY_BANDID) continue;
453 if(NSWL1::PAD::contains(line, NSWL1::SEMICOLON)) continue;
454 if(NSWL1::PAD::contains(words, NSWL1::VHDLCOMMENT)) continue;
455 if(std::any_of(std::begin(line), std::end(line), [](char c){ return std::isalpha(c); })) continue;
456 if(words.size() < NSWL1::NLAYERS) continue;
457 ATH_MSG_DEBUG("Skipped uninteresting lines");
458
459 // clean up the line
460 line = NSWL1::PAD::replace(line, ",", ", ");
461 line = NSWL1::PAD::replace(line, "(", " ");
462 line = NSWL1::PAD::replace(line, ")", " ");
463 line = NSWL1::PAD::replace(line, "0-1", "-1");
464 line = NSWL1::PAD::replace(line, " ", "");
465 const auto vals = CxxUtils::tokenize(line, NSWL1::COMMA);
466 if(vals.size() != NSWL1::PAD::PATTERNLEN) {
467 throw std::runtime_error("Can't unpack " + line);
468 }
469 ATH_MSG_DEBUG("Cleaned up lines");
470
471 // unpack the line
472 const auto pfeb0 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PFEB0)));
473 const auto pfeb1 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PFEB1)));
474 const auto pfeb2 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PFEB2)));
475 const auto pfeb3 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PFEB3)));
476 const auto pfeb4 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PFEB4)));
477 const auto pfeb5 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PFEB5)));
478 const auto pfeb6 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PFEB6)));
479 const auto pfeb7 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PFEB7)));
480
481 const auto padchan0 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PADCHAN0)));
482 const auto padchan1 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PADCHAN1)));
483 const auto padchan2 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PADCHAN2)));
484 const auto padchan3 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PADCHAN3)));
485 const auto padchan4 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PADCHAN4)));
486 const auto padchan5 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PADCHAN5)));
487 const auto padchan6 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PADCHAN6)));
488 const auto padchan7 = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PADCHAN7)));
489 const auto phiid = static_cast<uint32_t>(std::stoul(vals.at(NSWL1::PAD::I_PHIID)));
490
491 // Store the retrieved information
492 const std::array<uint32_t,8> pfebs = {pfeb0, pfeb1, pfeb2, pfeb3, pfeb4, pfeb5, pfeb6, pfeb7};
493 const std::array<uint32_t,8> padchans = {padchan0, padchan1, padchan2, padchan3, padchan4, padchan5, padchan6, padchan7};
494
495 // Save information in the private member of the class
496 if(isLarge) m_patterns_L.emplace_back( PadPattern(bandid, phiid, pfebs, padchans, isLarge) );
497 else m_patterns_S.emplace_back( PadPattern(bandid, phiid, pfebs, padchans, isLarge) );
498 ATH_MSG_DEBUG("Unpacked lines and info stored");
499 }
500 }
501 else {
502 ATH_MSG_ERROR("Unable to read pad pattern file. No pattern will be loaded");
503 return StatusCode::FAILURE;
504 }
505 ifs.close();
506 ATH_MSG_DEBUG("Successfully loaded list of patterns from " << pfile << " with size (L/S): " << m_patterns_L.size() << " / " << m_patterns_S.size());
507 return StatusCode::SUCCESS;
508 }
509
510 /*
511 ***** Mask patterns, according to known issues, when initializing the algorithm tool
512 */
514 std::vector<char> sectorSizes = {'L', 'S'};
515 for(const auto& secSize: sectorSizes) {
516 const bool isLarge = (secSize == 'L');
517 const std::vector<PadPattern> patterns = (isLarge) ? m_patterns_L : m_patterns_S;
518 for(uint32_t patternitter{0}; patternitter < patterns.size(); ++patternitter) {
519 const auto& pattern = patterns.at(patternitter);
520 const auto pads = pattern.getPadChannels();
521 uint32_t mask{0};
522 bool ipfake = NSWL1::PAD::isDummyPad(pads.at(0));
523 bool hofake = NSWL1::PAD::isDummyPad(pads.at(4));
524 bool is4layer = (ipfake || hofake);
525
526 std::map<std::string, uint32_t> problematicSectors{};
527 if(is4layer) {
528 int offset = (ipfake) ? 0 : 4;
529 mask |= (1 << offset);
530 if (m_triggerLogic != "specific4over8") mask |= (1 << (offset + 1));
531 if (m_triggerLogic == "8over8" || m_triggerLogic == "2x3over4" || m_triggerLogic == "specific4over8") mask |= (1 << (offset + 2));
532 if (m_triggerLogic == "8over8") mask |= (1 << (offset + 3));
533 for (const auto& wheel: NSWL1::WHEELS) {
534 for (const auto& sector: NSWL1::PAD::SECTORS) {
535 if (isLarge != (sector%2 == 0)) continue;
536 std::string secname = wheel + std::to_string(sector+1);
537 problematicSectors.try_emplace(secname, mask);
538 }
539 }
540 }
541
542 if(problematicSectors.empty()) continue;
543 for(const auto& sectoritr : problematicSectors) {
544 const auto sector = sectoritr.first;
545 m_maskedPatterns.try_emplace(sector, std::vector<std::tuple<uint32_t, uint32_t>>());
546 m_maskedPatterns.at(sector).push_back(std::make_tuple(patternitter, sectoritr.second));
547 }
548 }
549 }
550
551 ATH_MSG_DEBUG("Found a total of " << m_maskedPatterns.size() << " patterns to be masked");
552 return StatusCode::SUCCESS;
553 }
554
555 /*
556 ***** Set ROB IDs when initializing the tool and to loop over them in the main algorithm loop
557 */
559 for(const auto& wheel : NSWL1::WHEELS) {
560 for(const auto& sector: NSWL1::PAD::SECTORS) {
562 }
563 }
564 return StatusCode::SUCCESS;
565 }
566}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
std::vector< uint32_t > getForbiddenBandIDs(const std::vector< PadEmulatorTrigger > &triggers, const bool isLarge) const
std::vector< PadEmulatorTrigger > filterPriorityEncoder(const std::vector< PadEmulatorTrigger > &input, const bool isLarge) const
Gaudi::Property< bool > m_isMC
Gaudi::Property< bool > m_doNtuple
SG::ReadCondHandleKey< NswDcsDbData > m_dcsKey
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_detectorManagerKey
Gaudi::Property< bool > m_lastPhiOnly
Gaudi::Property< std::string > m_triggerLogic
StatusCode loadPatterns(const std::string &pfile)
std::vector< PadEmulatorTrigger > filterLowBandIDs(const std::vector< PadEmulatorTrigger > &input) const
SG::ReadHandleKey< sTgcDigitContainer > m_sTGCDigitContainerKey
std::map< std::string, std::vector< std::tuple< uint32_t, uint32_t > > > m_maskedPatterns
Gaudi::Property< bool > m_ignoreBCIDs
virtual StatusCode attachBranches(MuonVal::MuonTesterTree &tree) override
Gaudi::Property< std::string > m_pattername_S
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
Gaudi::Property< bool > m_noDuplicates
std::vector< PadPattern > m_patterns_S
std::vector< PadEmulatorTrigger > filterLastPhiOnly(const std::vector< PadEmulatorTrigger > &input) const
Gaudi::Property< std::string > m_pattername_L
std::vector< uint32_t > m_robIDs
PadEmulatorTool(const std::string &type, const std::string &name, const IInterface *parent)
virtual StatusCode initialize() override
Gaudi::Property< bool > m_bandIDPriorityEncode
std::vector< PadEmulatorTrigger > filterDuplicates(const std::vector< PadEmulatorTrigger > &input) const
Gaudi::Property< unsigned short > m_stretch
std::vector< PadPattern > m_patterns_L
virtual StatusCode emulate(const EventContext &ctx, Muon::NSW_PadTriggerDataContainer *out) const override
bool isGoodEltx(const Identifier &channelId) const
bool isGood(const EventContext &ctx, const Identifier &channelId, bool issTgcQ1OuterHv=false) const
Returns whether the channel is alive, i.e. DCS state on, etc...
bool isConnectedChannel(const Identifier &channelId) const
bool isGoodHv(const Identifier &channelId, bool issTgcQ1OuterHv=false) const
bool isGoodTDaq(const EventContext &ctx, const Identifier &channelId, bool &permanentlyDisabled) const
const_pointer_type cptr()
virtual bool isValid() override final
Can the handle be successfully dereferenced?
std::vector< std::string > patterns
Definition listroot.cxx:187
std::vector< std::string > tokenize(const std::string &the_str, std::string_view delimiters)
Splits the string into smaller substrings.
constexpr size_t I_PADCHAN1
constexpr size_t I_PFEB7
uint32_t priorityEncoderS(uint32_t bandid)
constexpr size_t I_PADCHAN0
constexpr size_t I_PADCHAN2
constexpr size_t I_PADCHAN7
constexpr uint32_t NPFEB_PER_RADIUS
constexpr size_t I_PHIID
constexpr size_t I_PFEB2
uint32_t priorityEncoderL(uint32_t bandid)
const std::string PATTERN_END
constexpr uint32_t PAD_TRIGGER_READOUT_NBC
uint32_t getPadchAthena(const int athCh, const int pfeb, const int sector, int gasGap)
bool contains(const std::string &str, const std::string &substr)
constexpr size_t I_PADCHAN6
bool isDummyPad(const uint32_t padchan)
constexpr size_t I_PFEB3
constexpr size_t I_PADCHAN3
constexpr size_t I_PFEB5
constexpr size_t I_PADCHAN4
const std::string PATTERN_TAG
const std::string LARGE
constexpr size_t I_PFEB1
uint32_t parseLineForBandid(const std::string &line)
uint32_t wheelSectorToSourceID(const char wheel, const uint32_t sector)
constexpr std::array< uint32_t, NSECTORS > SECTORS
constexpr size_t PATTERNLEN
constexpr uint32_t MUON_STGC_ENDCAP_A_SIDE
constexpr size_t I_PFEB0
constexpr size_t I_PFEB6
constexpr size_t I_PFEB4
constexpr uint32_t PAD_TRIGGER_ROB
uint32_t getpFEBAthena(const int gas_gap, const int multiplet, const int stationEta)
constexpr uint32_t DUMMY_BANDID
constexpr size_t I_PADCHAN5
std::string replace(std::string subject, const std::string &search, const std::string &replace)
constexpr uint32_t MUON_STGC_ENDCAP_C_SIDE
PadEmulatorCoincidences.
bool trigger_superspecific5over8(const bool in0, const bool in1, const bool in2, const bool in3, const bool in4, const bool in5, const bool in6, const bool in7)
bool isA(const uint32_t sourceid)
const std::vector< std::string > WHEELS
const std::string COMMA
const std::string SEMICOLON
constexpr uint32_t NLAYERS
bool trigger_2and2(const bool in0, const bool in1, const bool in2, const bool in3, const bool in4, const bool in5, const bool in6, const bool in7)
bool trigger_6over8(const bool in0, const bool in1, const bool in2, const bool in3, const bool in4, const bool in5, const bool in6, const bool in7)
bool trigger_4over8(const bool in0, const bool in1, const bool in2, const bool in3, const bool in4, const bool in5, const bool in6, const bool in7)
bool trigger_specific4over8(const bool in0, const bool in1, const bool in2, const bool in3, const bool in4, const bool in5, const bool in6, const bool in7)
bool trigger_3and1(const bool in0, const bool in1, const bool in2, const bool in3, const bool in4, const bool in5, const bool in6, const bool in7)
const std::string SPACE
const std::string VHDLCOMMENT
bool trigger_8over8(const bool in0, const bool in1, const bool in2, const bool in3, const bool in4, const bool in5, const bool in6, const bool in7)
bool trigger_2X_3over4(const bool in0, const bool in1, const bool in2, const bool in3, const bool in4, const bool in5, const bool in6, const bool in7)
bool trigger_specific5over8(const bool in0, const bool in1, const bool in2, const bool in3, const bool in4, const bool in5, const bool in6, const bool in7)
bool trigger_5over8(const bool in0, const bool in1, const bool in2, const bool in3, const bool in4, const bool in5, const bool in6, const bool in7)
Definition index.py:1
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
TChain * tree