ATLAS Offline Software
Loading...
Searching...
No Matches
L1CorrelationAlg.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 "L1CorrelationAlg.h"
6#include "CTPfragment/CTPfragment.h"
7#include "CTPfragment/CTPdataformat.h"
8
12
13L1CorrelationAlg::L1CorrelationAlg(const std::string& name, ISvcLocator* pSvcLocator) : AthReentrantAlgorithm(name, pSvcLocator) {}
14
16
18 ATH_CHECK(m_trigCompositeKey.initialize());
19 ATH_CHECK(m_l1MenuKey.initialize());
20 ATH_CHECK(m_passKey.initialize());
21 ATH_CHECK(m_l1AKey.initialize());
22 ATH_CHECK(m_otherTypeKey.initialize());
23 ATH_CHECK(m_beforeAfterKey.initialize());
24 ATH_CHECK(m_otherTypeBeforeKey.initialize());
25 ATH_CHECK(m_otherTypeAfterKey.initialize());
26 ATH_CHECK(m_beforeOffsetKey.initialize());
27 ATH_CHECK(m_afterOffsetKey.initialize());
28 ATH_CHECK(m_monTool.retrieve());
29
30 return StatusCode::SUCCESS;
31}
32
34
35 //get L1 menu and initialise bitMasks based on l1 em/j/mu triggers
37 ATH_CHECK(rh_l1Menu.isValid());
38
39 std::vector<int> ctpids_ele;
40 std::vector<int> ctpids_mu;
41 std::vector<int> ctpids_jets;
42 std::vector<int> ctpids;
43
44 for(const TrigConf::L1Item& item : *rh_l1Menu){
45 for(unsigned int nl1=0; nl1<m_l1itemlist.size(); nl1++){
46 if(m_l1itemlist[nl1].compare(item.name()) == 0 ){
47 ATH_MSG_DEBUG("L1CorrAlgInit: Configured to use item:" <<item.name().c_str()<< " CTPID:"<<item.ctpId());
48 ctpids.push_back( item.ctpId() );
49 if( m_l1itemlist[nl1].find( "L1_EM" ) != std::string::npos ){
50 ctpids_ele.push_back( item.ctpId() );
51 }
52 if( m_l1itemlist[nl1].find( "L1_MU" ) != std::string::npos ){
53 ctpids_mu.push_back( item.ctpId() );
54 }
55 if(( m_l1itemlist[nl1].find( "L1_J") != std::string::npos ) || ( m_l1itemlist[nl1].find( "L1_jJ" ) != std::string::npos)){
56 ctpids_jets.push_back( item.ctpId() );
57 }
58 }
59 }
60 }
61
62 // init with 0
63 m_bitmasks.clear();
64 m_bitmasks_ele.clear();
65 m_bitmasks_mu.clear();
66 m_bitmasks_jets.clear();
67 for(int n=0; n<16 ; n++){
68 uint32_t tmpword=0;
69 m_bitmasks.push_back(tmpword);
70 m_bitmasks_ele.push_back(tmpword);
71 m_bitmasks_mu.push_back(tmpword);
72 m_bitmasks_jets.push_back(tmpword);
73 }
74
75 //all ctpids
76 for(unsigned int n=0; n<ctpids.size() ; n++){
77 // check in which word it belongs
78 int cycle = ctpids[n] / 32;
79 int pos = ctpids[n] % 32;
80
81 uint32_t currentmask = m_bitmasks[cycle];
82 uint32_t tmpmask = 1;
83 // shift this pos positions to left
84 tmpmask = tmpmask << (pos);
85
86 // OR this with the existing mask
87 m_bitmasks[cycle] = tmpmask | currentmask;
88 }
89
90 //electrons
91 for(unsigned int n=0; n<ctpids_ele.size() ; n++){
92 // check in which word it belongs
93 int cycle = ctpids_ele[n] / 32;
94 int pos = ctpids_ele[n] % 32;
95
96 uint32_t currentmask = m_bitmasks_ele[cycle];
97 uint32_t tmpmask = 1;
98 // shift this pos positions to left
99 tmpmask = tmpmask << (pos);
100
101 // OR this with the existing mask
102 m_bitmasks_ele[cycle] = tmpmask | currentmask;
103 }
104
105 //muons
106 for(unsigned int n=0; n<ctpids_mu.size() ; n++){
107 // check in which word it belongs
108 int cycle = ctpids_mu[n] / 32;
109 int pos = ctpids_mu[n] % 32;
110
111 uint32_t currentmask = m_bitmasks_mu[cycle];
112 uint32_t tmpmask = 1;
113 // shift this pos positions to left
114 tmpmask = tmpmask << (pos);
115
116 // OR this with the existing mask
117 m_bitmasks_mu[cycle] = tmpmask | currentmask;
118 }
119
120 //jets
121 for(unsigned int n=0; n<ctpids_jets.size() ; n++){
122 // check in which word it belongs
123 int cycle = ctpids_jets[n] / 32;
124 int pos = ctpids_jets[n] % 32;
125
126 uint32_t currentmask = m_bitmasks_jets[cycle];
127 uint32_t tmpmask = 1;
128 // shift this pos positions to left
129 tmpmask = tmpmask << (pos);
130
131 // OR this with the existing mask
132 m_bitmasks_jets[cycle] = tmpmask | currentmask;
133 }
134
135 return StatusCode::SUCCESS;
136}
137
138
139StatusCode L1CorrelationAlg::execute(const EventContext& ctx) const {
140
141 //TrigComposite Container to record
143 ATH_CHECK(wh_trigComposite.record(std::make_unique<xAOD::TrigCompositeContainer>(), std::make_unique<xAOD::TrigCompositeAuxContainer>()));
144 auto trigCompCont = wh_trigComposite.ptr();
145
154
155 //CTP ROB
156 std::vector<const OFFLINE_FRAGMENTS_NAMESPACE::ROBFragment*> robFragments;
157 std::vector<uint32_t> roblist;
158 // magic number!
159 roblist.push_back(0x770000);
160 m_robDataProviderSvc->addROBData(ctx, roblist);
161 m_robDataProviderSvc->getROBData(ctx, roblist, robFragments);
162 if (msgLvl(MSG::DEBUG)) {
163 std::ostringstream os;
164 for(auto rob : roblist){
165 os << std::hex<<rob;
166 }
167 ATH_MSG_DEBUG(roblist.size() << "/" << robFragments.size()
168 << " ROBs requested/retrieved:" << os.str());
169 }
170 if (robFragments.size()<1){
171 ATH_MSG_DEBUG("Could not retrieve ROB!");
172 return StatusCode::SUCCESS;
173 }
174 const eformat::ROBFragment<const uint32_t*>* rbf = robFragments[0];
175
176 // L1A index within the CTP readout window (not a BCID).
177 // For a symmetric window nBC = 2*k + 1, L1A sits at index k:
178 // e.g. ±1 → nBC=3 → l1a_idx=1; ±2 → nBC=5 → l1a_idx=2.
179 const int l1a_idx = static_cast<int>(CTPfragment::lvl1AcceptBunch(rbf)); // index in readout window
180
181 const int nBC = 2 * l1a_idx + 1; // symmetric by requirement
182 const int mid = l1a_idx; // central element
183
184 // Cache TBP/TAP once per BC
185 std::vector<std::vector<uint32_t>> tbpWords(nBC), tapWords(nBC);
186 for (int i = 0; i < nBC; ++i) {
187 const unsigned k = static_cast<unsigned>(i);
188 tbpWords[i] = CTPfragment::triggerDecisionBeforePrescales(rbf, k);
189 tapWords[i] = CTPfragment::triggerDecisionAfterPrescales (rbf, k);
190 }
191
192 // Helper: any-bit-on under mask
193 auto firedFromWords = [&](const std::vector<uint32_t>& w,
194 const std::vector<uint32_t>& mask) -> uint8_t {
195 const std::size_t nw = std::min(w.size(), mask.size()); // (16 by design)
196 uint8_t on = 0;
197 for (std::size_t iw = 0; iw < nw; ++iw) on |= static_cast<uint8_t>((w[iw] & mask[iw]) != 0u);
198 return on;
199 };
200
201 // Per-BC fired flags (TBP)
202 std::vector<uint8_t> firedbc(nBC,0), firedbc_ele(nBC,0), firedbc_mu(nBC,0), firedbc_jet(nBC,0);
203 for (int i = 0; i < nBC; ++i) {
204 firedbc [i] = firedFromWords(tbpWords[i], m_bitmasks);
205 firedbc_ele[i] = firedFromWords(tbpWords[i], m_bitmasks_ele);
206 firedbc_mu [i] = firedFromWords(tbpWords[i], m_bitmasks_mu );
207 firedbc_jet[i] = firedFromWords(tbpWords[i], m_bitmasks_jets);
208 }
209
210 // Central-BC inclusion flag
211 if (m_currentBCincl) {
212 firedbc[mid] = firedbc_ele[mid] = firedbc_mu[mid] = firedbc_jet[mid] = 1;
213 }
214
215 // Occupancy maps (delta BC, CTPID) for TBP/TAP
216 auto collect_ids_from_words = [this](const std::vector<uint32_t>& words) {
217 std::vector<int> ids;
218 const std::size_t nw = std::min(words.size(), this->m_bitmasks.size()); // typically 16
219 ids.reserve(32u * nw);
220 for (std::size_t iw = 0; iw < nw; ++iw) {
221 uint32_t w = words[iw];
222 if (!w) continue;
223 const unsigned base = static_cast<unsigned>(iw * 32u);
224 for (unsigned b = 0; b < 32; ++b) if (w & (1u << b)) ids.emplace_back(static_cast<int>(base + b));
225 }
226 return ids;
227 };
228
229 std::vector<int> vDeltaBC_all_TBP, vCtpId_all_TBP, vDeltaBC_all_TAP, vCtpId_all_TAP;
230 vDeltaBC_all_TBP.reserve(64); vCtpId_all_TBP.reserve(64);
231 vDeltaBC_all_TAP.reserve(64); vCtpId_all_TAP.reserve(64);
232
233 for (int i = 0; i < nBC; ++i) {
234 const int delta = i - mid;
235 {
236 const auto ids = collect_ids_from_words(tbpWords[i]);
237 vDeltaBC_all_TBP.insert(vDeltaBC_all_TBP.end(), ids.size(), delta);
238 vCtpId_all_TBP.insert (vCtpId_all_TBP.end(), ids.begin(), ids.end());
239 }
240 {
241 const auto ids = collect_ids_from_words(tapWords[i]);
242 vDeltaBC_all_TAP.insert(vDeltaBC_all_TAP.end(), ids.size(), delta);
243 vCtpId_all_TAP.insert (vCtpId_all_TAP.end(), ids.begin(), ids.end());
244 }
245 }
246
247 // Pass–fail decision: nearest neighbour on each side
248 int isPassed = 0;
249 int beforeafterflag = 0; // sign: side; abs: offset
250 int offset_before = 0, offset_after = 0;
251 for (int d = 1; d <= l1a_idx; ++d) {
252 if (firedbc[mid] && firedbc[mid - d] && offset_before == 0) { offset_before = d; isPassed = 1; }
253 if (firedbc[mid] && firedbc[mid + d] && offset_after == 0) { offset_after = d; isPassed = 1; }
254 if (offset_before && offset_after) break;
255 }
256
257 // Classification (legacy 1..7)
258 auto classify = [&](int idx)->int {
259 if (firedbc_ele[idx] && !firedbc_mu[idx] && !firedbc_jet[idx]) return 1;
260 else if (firedbc_mu [idx] && !firedbc_ele[idx] && !firedbc_jet[idx]) return 2;
261 else if (firedbc_jet[idx] && !firedbc_ele[idx] && !firedbc_mu[idx]) return 3;
262 else if (firedbc_ele[idx] && firedbc_mu[idx] && !firedbc_jet[idx]) return 4;
263 else if (firedbc_ele[idx] && firedbc_jet[idx] && !firedbc_mu[idx]) return 5;
264 else if (firedbc_mu [idx] && firedbc_jet[idx] && !firedbc_ele[idx]) return 6;
265 else if (firedbc_ele[idx] && firedbc_mu[idx] && firedbc_jet[idx]) return 7;
266 return 0;
267 };
268
269 int l1a_type = classify(mid);
270 int other_type_before = (offset_before > 0) ? classify(mid - offset_before) : 0;
271 int other_type_after = (offset_after > 0) ? classify(mid + offset_after ) : 0;
272
273 // Choose operative side
274 if (offset_before > 0 && offset_after > 0) {
275 if (offset_before < offset_after) beforeafterflag = -offset_before;
276 else if (offset_after < offset_before) beforeafterflag = +offset_after;
277 else beforeafterflag = +offset_after; // tie → positive side
278 } else if (offset_before > 0) {
279 beforeafterflag = -offset_before;
280 } else if (offset_after > 0) {
281 beforeafterflag = +offset_after;
282 }
283
284 int other_type = 0;
285 if (beforeafterflag < 0) other_type = other_type_before;
286 else if (beforeafterflag > 0) other_type = other_type_after;
287
288 // Create TrigComposite only if passed
289 if (isPassed) {
290 auto trigComp = new xAOD::TrigComposite();
291 trigCompCont->push_back(trigComp);
292 trigComp->setName("mistimemon_L1Dec");
293
294 trigCompL1A (*trigComp) = l1a_type;
295 trigCompOther (*trigComp) = other_type;
296 trigCompBeforeAfter (*trigComp) = beforeafterflag;
297 trigCompPass (*trigComp) = isPassed;
298 trigCompOtherBefore (*trigComp) = other_type_before;
299 trigCompOtherAfter (*trigComp) = other_type_after;
300 trigCompBeforeOffset(*trigComp) = offset_before;
301 trigCompAfterOffset (*trigComp) = offset_after;
302 }
303
304 // Monitoring: global summary + side-specific
305 auto mon_l1a = Monitored::Scalar<int>("l1Accept", l1a_type);
306 auto mon_otherType = Monitored::Scalar<int>("otherType", other_type);
307 auto mon_beforeAfter = Monitored::Scalar<int>("BeforeAfterFlag", beforeafterflag);
308 auto monitorIt = Monitored::Group(m_monTool, mon_l1a, mon_otherType, mon_beforeAfter);
309
310 if (offset_before > 0 && offset_after > 0) {
311 auto mon_offsetBefore = Monitored::Scalar<int>("BeforeOffset", offset_before);
312 auto mon_offsetAfter = Monitored::Scalar<int>("AfterOffset", offset_after);
313 auto mon_otherBefore = Monitored::Scalar<int>("OtherTypeBefore", other_type_before);
314 auto mon_otherAfter = Monitored::Scalar<int>("OtherTypeAfter", other_type_after);
315 auto gBoth = Monitored::Group(m_monTool, mon_offsetBefore, mon_offsetAfter, mon_otherBefore, mon_otherAfter);
316 (void)gBoth;
317 } else if (offset_before > 0) {
318 auto mon_offsetBefore = Monitored::Scalar<int>("BeforeOffset", offset_before);
319 auto mon_otherBefore = Monitored::Scalar<int>("OtherTypeBefore", other_type_before);
320 auto gB = Monitored::Group(m_monTool, mon_offsetBefore, mon_otherBefore);
321 (void)gB;
322 } else if (offset_after > 0) {
323 auto mon_offsetAfter = Monitored::Scalar<int>("AfterOffset", offset_after);
324 auto mon_otherAfter = Monitored::Scalar<int>("OtherTypeAfter", other_type_after);
325 auto gA = Monitored::Group(m_monTool, mon_offsetAfter, mon_otherAfter);
326 (void)gA;
327 }
328
329 // Full occupancy maps (TBP/TAP)
330 auto mon_dbc_all_tbp = Monitored::Collection("DeltaBCAll", vDeltaBC_all_TBP);
331 auto mon_id_all_tbp = Monitored::Collection("CTPIDAll", vCtpId_all_TBP);
332 auto mon_dbc_all_tap = Monitored::Collection("DeltaBCAll_TAP", vDeltaBC_all_TAP);
333 auto mon_id_all_tap = Monitored::Collection("CTPIDAll_TAP", vCtpId_all_TAP);
334 auto gMaps = Monitored::Group(m_monTool, mon_dbc_all_tbp, mon_id_all_tbp,
335 mon_dbc_all_tap, mon_id_all_tap);
336 (void)gMaps;
337
338 // Pair maps at abs(delta) = 1,2,3... (using cached words)
339 const auto ids0_tbp = collect_ids_from_words(tbpWords[mid]);
340 const auto ids0_tap = collect_ids_from_words(tapWords[mid]);
341
342 auto fill_pair_map = [&](int deltaSel, bool useTAP,
343 const char* varX, const char* varY) {
344 const int kN = mid + deltaSel;
345 if (kN < 0 || kN >= nBC) return;
346
347 const auto &idsN = useTAP ? collect_ids_from_words(tapWords[kN])
348 : collect_ids_from_words(tbpWords[kN]);
349 const auto& ids0 = useTAP ? ids0_tap : ids0_tbp;
350
351 if (ids0.empty() || idsN.empty()) return;
352
353 std::vector<int> vId0; vId0.reserve(ids0.size() * idsN.size());
354 std::vector<int> vIdN; vIdN.reserve(vId0.capacity());
355 for (int id0 : ids0) for (int idN : idsN) { vId0.emplace_back(id0); vIdN.emplace_back(idN); }
356
357 auto mon_x = Monitored::Collection(varX, vId0);
358 auto mon_y = Monitored::Collection(varY, vIdN);
359 auto g = Monitored::Group(m_monTool, mon_x, mon_y);
360 (void)g;
361 };
362
363 // TBP: delta = +2, −2, +1, −1
364 fill_pair_map(+2, false, "CTPID0tbp_p2", "CTPIDtbp_p2");
365 fill_pair_map(-2, false, "CTPID0tbp_m2", "CTPIDtbp_m2");
366 fill_pair_map(+1, false, "CTPID0tbp_p1", "CTPIDtbp_p1");
367 fill_pair_map(-1, false, "CTPID0tbp_m1", "CTPIDtbp_m1");
368
369 // TAP: delta = +2, −2, +1, −1
370 fill_pair_map(+2, true , "CTPID0tap_p2", "CTPIDtap_p2");
371 fill_pair_map(-2, true , "CTPID0tap_m2", "CTPIDtap_m2");
372 fill_pair_map(+1, true , "CTPID0tap_p1", "CTPIDtap_p1");
373 fill_pair_map(-1, true , "CTPID0tap_m1", "CTPIDtap_m1");
374
375 return StatusCode::SUCCESS;
376}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x)
Header file to be included by clients of the Monitored infrastructure.
double cycle(double a, double b)
Handle class for adding a decoration to an object.
bool msgLvl(const MSG::Level lvl) const
An algorithm that can be simultaneously executed in multiple threads.
virtual StatusCode execute(const EventContext &ctx) const override
SG::WriteDecorHandleKey< xAOD::TrigCompositeContainer > m_otherTypeBeforeKey
SG::WriteDecorHandleKey< xAOD::TrigCompositeContainer > m_otherTypeKey
SG::WriteDecorHandleKey< xAOD::TrigCompositeContainer > m_beforeOffsetKey
SG::WriteHandleKey< xAOD::TrigCompositeContainer > m_trigCompositeKey
std::vector< uint32_t > m_bitmasks
SG::ReadHandleKey< TrigConf::L1Menu > m_l1MenuKey
Gaudi::Property< bool > m_currentBCincl
std::vector< uint32_t > m_bitmasks_ele
SG::WriteDecorHandleKey< xAOD::TrigCompositeContainer > m_otherTypeAfterKey
Gaudi::Property< std::vector< std::string > > m_l1itemlist
SG::WriteDecorHandleKey< xAOD::TrigCompositeContainer > m_afterOffsetKey
std::vector< uint32_t > m_bitmasks_jets
L1CorrelationAlg(const std::string &name, ISvcLocator *pSvcLocator)
ToolHandle< GenericMonitoringTool > m_monTool
virtual StatusCode start() override
ServiceHandle< IROBDataProviderSvc > m_robDataProviderSvc
virtual StatusCode initialize() override
std::vector< uint32_t > m_bitmasks_mu
SG::WriteDecorHandleKey< xAOD::TrigCompositeContainer > m_l1AKey
SG::WriteDecorHandleKey< xAOD::TrigCompositeContainer > m_beforeAfterKey
SG::WriteDecorHandleKey< xAOD::TrigCompositeContainer > m_passKey
Group of local monitoring quantities and retain correlation when filling histograms
Declare a monitored scalar variable.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
Handle class for adding a decoration to an object.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
pointer_type ptr()
Dereference the pointer.
L1 threshold configuration.
Definition L1Item.h:18
std::string find(const std::string &s)
return a remapped string
Definition hcg.cxx:138
std::string base
Definition hcg.cxx:81
ValuesCollection< T > Collection(std::string name, const T &collection)
Declare a monitored (double-convertible) collection.
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
TrigComposite_v1 TrigComposite
Declare the latest version of the class.