2727#include " EMCALBase/Geometry.h"
2828#include " EMCALCalib/BadChannelMap.h"
2929#include " EMCALCalib/TimeCalibrationParams.h"
30+ #include < Framework/ConcreteDataMatcher.h>
31+ #include < Framework/DataRefUtils.h>
32+ #include < Framework/DataSpecUtils.h>
3033#include < Framework/InputRecord.h>
34+ #include < Framework/InputRecordWalker.h>
3135#include < CommonConstants/Triggers.h>
3236
3337namespace o2
@@ -98,22 +102,46 @@ void DigitsQcTask::monitorData(o2::framework::ProcessingContext& ctx)
98102 }
99103 }
100104
101- // Get payload and loop over digits
102- auto digitcontainer = ctx.inputs ().get <gsl::span<o2::emcal::Cell>>(" emcal-digits" ); // it was emcal::Digit
103- auto triggerrecords = ctx.inputs ().get <gsl::span<o2::emcal::TriggerRecord>>(" emcal-triggerecords" );
105+ // Handling of inputs from multiple subevents (multiple FLPs)
106+ // Build maps of trigger records and cells according to the subspecification
107+ // and combine trigger records from different maps into a single map of range
108+ // references and subspecifications
109+ std::vector<framework::InputSpec> cellInputs{ { " cellfilter" , framework::ConcreteDataTypeMatcher (header::gDataOriginEMC , " CELLS" ) } },
110+ triggerRecordInputs{ { " triggerrecordfilter" , framework::ConcreteDataTypeMatcher (header::gDataOriginEMC , " CELLSTRGR" ) } };
111+ std::map<int , gsl::span<const o2::emcal::Cell>> cellSubEvents;
112+ std::map<int , gsl::span<const o2::emcal::TriggerRecord>> triggerRecordSubevents;
113+ for (const auto & celldata : framework::InputRecordWalker (ctx.inputs (), cellInputs)) {
114+ int ncell = framework::DataRefUtils::getPayloadSize (celldata) / sizeof (o2::emcal::Cell);
115+ int subspecification = 0 ;
116+ auto subspecval = framework::DataSpecUtils::getOptionalSubSpec (*celldata.spec );
117+ if (subspecval.has_value ())
118+ subspecification = *subspecval;
119+ auto data = gsl::span<const o2::emcal::Cell>(reinterpret_cast <o2::emcal::Cell const *>(celldata.payload ), ncell);
120+ cellSubEvents[subspecification] = data;
121+ }
122+
123+ for (const auto & triggerrecdata : framework::InputRecordWalker (ctx.inputs (), triggerRecordInputs)) {
124+ int ntriggerrecords = framework::DataRefUtils::getPayloadSize (triggerrecdata) / sizeof (o2::emcal::TriggerRecord);
125+ int subspecification = 0 ;
126+ auto subspecval = framework::DataSpecUtils::getOptionalSubSpec (*triggerrecdata.spec );
127+ if (subspecval.has_value ())
128+ subspecification = *subspecval;
129+ auto data = gsl::span<const o2::emcal::TriggerRecord>(reinterpret_cast <o2::emcal::TriggerRecord const *>(triggerrecdata.payload ), ntriggerrecords);
130+ triggerRecordSubevents[subspecification] = data;
131+ }
132+
133+ auto combinedEvents = buildCombinedEvents (triggerRecordSubevents);
104134
105135 // QcInfoLogger::GetInstance() << "Received " << digitcontainer.size() << " digits " << AliceO2::InfoLogger::InfoLogger::endm;
106136 int eventcounter = 0 ;
107- for (auto trg : triggerrecords ) {
137+ for (auto trg : combinedEvents ) {
108138 if (!trg.getNumberOfObjects ()) {
109139 continue ;
110140 }
111-
112141 QcInfoLogger::GetInstance () << QcInfoLogger::Debug << " Next event " << eventcounter << " has " << trg.getNumberOfObjects () << " digits" << QcInfoLogger::endm;
113- gsl::span<const o2::emcal::Cell> eventdigits (digitcontainer.data () + trg.getFirstEntry (), trg.getNumberOfObjects ());
114142
115143 // trigger type
116- auto triggertype = trg.getTriggerBits () ;
144+ auto triggertype = trg.mTriggerType ;
117145 bool isPhysTrigger = triggertype & o2::trigger::PhT, isCalibTrigger = triggertype & o2::trigger::Cal;
118146 std::string trgClass;
119147 if (isPhysTrigger) {
@@ -127,44 +155,53 @@ void DigitsQcTask::monitorData(o2::framework::ProcessingContext& ctx)
127155
128156 auto histos = mHistogramContainer [trgClass];
129157
130- for (auto digit : eventdigits) {
131- int index = digit.getHighGain () ? 0 : (digit.getLowGain () ? 1 : -1 );
132- if (index < 0 )
133- continue ;
134- auto cellindices = mGeometry ->GetCellIndex (digit.getTower ());
135-
136- histos.mDigitAmplitude [index]->Fill (digit.getEnergy (), digit.getTower ());
137-
138- auto timeoffset = mTimeCalib ? mTimeCalib ->getTimeCalibParam (digit.getTower (), digit.getLowGain ()) : 0 .;
139-
140- if (!mBadChannelMap || (mBadChannelMap ->getChannelStatus (digit.getTower ()) == MaskType_t::GOOD_CELL)) {
141- histos.mDigitAmplitudeCalib [index]->Fill (digit.getEnergy (), digit.getTower ());
142- histos.mDigitTimeCalib [index]->Fill (digit.getTimeStamp () - timeoffset, digit.getTower ());
143- }
144- histos.mDigitTime [index]->Fill (digit.getTimeStamp (), digit.getTower ());
145-
146- // get the supermodule for filling EMCAL/DCAL spectra
147-
148- try {
149-
150- auto [row, col] = mGeometry ->GlobalRowColFromIndex (digit.getTower ());
151- if (digit.getEnergy () > 0 ) {
152- histos.mDigitOccupancy ->Fill (col, row);
153- }
154- if (digit.getEnergy () > mCellThreshold ) {
155- histos.mDigitOccupancyThr ->Fill (col, row);
158+ // iterate over subevents
159+ for (auto & subev : trg.mSubevents ) {
160+ auto cellsSubspec = cellSubEvents.find (subev.mSpecification );
161+ if (cellsSubspec == cellSubEvents.end ()) {
162+ QcInfoLogger::GetInstance () << QcInfoLogger::Error << " No cell data found for subspecification " << subev.mSpecification << QcInfoLogger::endm;
163+ } else {
164+ gsl::span<const o2::emcal::Cell> eventdigits (cellsSubspec->second .data () + subev.mCellRange .getFirstEntry (), subev.mCellRange .getEntries ());
165+ for (auto digit : eventdigits) {
166+ int index = digit.getHighGain () ? 0 : (digit.getLowGain () ? 1 : -1 );
167+ if (index < 0 )
168+ continue ;
169+ auto cellindices = mGeometry ->GetCellIndex (digit.getTower ());
170+ histos.mDigitAmplitude [index]->Fill (digit.getEnergy (), digit.getTower ());
171+
172+ auto timeoffset = mTimeCalib ? mTimeCalib ->getTimeCalibParam (digit.getTower (), digit.getLowGain ()) : 0 .;
173+
174+ if (!mBadChannelMap || (mBadChannelMap ->getChannelStatus (digit.getTower ()) == MaskType_t::GOOD_CELL)) {
175+ histos.mDigitAmplitudeCalib [index]->Fill (digit.getEnergy (), digit.getTower ());
176+ histos.mDigitTimeCalib [index]->Fill (digit.getTimeStamp () - timeoffset, digit.getTower ());
177+ }
178+ histos.mDigitTime [index]->Fill (digit.getTimeStamp (), digit.getTower ());
179+
180+ // get the supermodule for filling EMCAL/DCAL spectra
181+
182+ try {
183+
184+ auto [row, col] = mGeometry ->GlobalRowColFromIndex (digit.getTower ());
185+ if (digit.getEnergy () > 0 ) {
186+ histos.mDigitOccupancy ->Fill (col, row);
187+ }
188+ if (digit.getEnergy () > mCellThreshold ) {
189+ histos.mDigitOccupancyThr ->Fill (col, row);
190+ }
191+ histos.mIntegratedOccupancy ->Fill (col, row, digit.getEnergy ());
192+
193+ if (std::get<0 >(cellindices) < 12 )
194+ histos.mDigitAmplitudeEMCAL ->Fill (digit.getEnergy ());
195+
196+ else
197+ histos.mDigitAmplitudeDCAL ->Fill (digit.getEnergy ());
198+ } catch (o2::emcal::InvalidCellIDException& e) {
199+ QcInfoLogger::GetInstance () << " Invalid cell ID: " << e.getCellID () << AliceO2::InfoLogger::InfoLogger::endm;
200+ };
156201 }
157- histos.mIntegratedOccupancy ->Fill (col, row, digit.getEnergy ());
158-
159- if (std::get<0 >(cellindices) < 12 )
160- histos.mDigitAmplitudeEMCAL ->Fill (digit.getEnergy ());
161-
162- else
163- histos.mDigitAmplitudeDCAL ->Fill (digit.getEnergy ());
164- } catch (o2::emcal::InvalidCellIDException& e) {
165- QcInfoLogger::GetInstance () << " Invalid cell ID: " << e.getCellID () << AliceO2::InfoLogger::InfoLogger::endm;
166- };
202+ }
167203 }
204+
168205 histos.mnumberEvents ->Fill (1 );
169206 eventcounter++;
170207 }
@@ -190,22 +227,60 @@ void DigitsQcTask::reset()
190227 }
191228}
192229
230+ std::vector<DigitsQcTask::CombinedEvent> DigitsQcTask::buildCombinedEvents (const std::map<int , gsl::span<const o2::emcal::TriggerRecord>>& triggerrecords) const
231+ {
232+ std::vector<DigitsQcTask::CombinedEvent> events;
233+
234+ // Search interaction records from all subevents
235+ std::set<o2::InteractionRecord> allInteractions;
236+ for (auto & [subspecification, trgrec] : triggerrecords) {
237+ for (auto rec : trgrec) {
238+ auto eventIR = rec.getBCData ();
239+ if (allInteractions.find (eventIR) == allInteractions.end ())
240+ allInteractions.insert (eventIR);
241+ }
242+ }
243+
244+ // iterate over all subevents for all bunch crossings
245+ for (auto collision : allInteractions) {
246+ CombinedEvent nextevent;
247+ nextevent.mInteractionRecord = collision;
248+ bool first = true ,
249+ hasSubevent = false ;
250+ for (auto [subspecification, records] : triggerrecords) {
251+ auto found = std::find_if (records.begin (), records.end (), [&collision](const o2::emcal::TriggerRecord& rec) { return rec.getBCData () == collision; });
252+ if (found != records.end ()) {
253+ hasSubevent = true ;
254+ if (first) {
255+ nextevent.mTriggerType = found->getTriggerBits ();
256+ first = false ;
257+ }
258+ nextevent.mSubevents .push_back ({ subspecification, o2::dataformats::RangeReference (found->getFirstEntry (), found->getNumberOfObjects ()) });
259+ }
260+ }
261+ }
262+ return events;
263+ }
264+
193265void DigitsQcTask::startPublishing (DigitsHistograms& histos)
194266{
195267 for (auto h : histos.mDigitAmplitude ) {
196268 getObjectsManager ()->startPublishing (h);
197269 }
198270
271+ /*
199272 for (auto h : histos.mDigitTime) {
200273 getObjectsManager()->startPublishing(h);
201274 }
275+ */
202276 for (auto h : histos.mDigitAmplitudeCalib ) {
203277 getObjectsManager ()->startPublishing (h);
204278 }
205-
279+ /*
206280 for (auto h : histos.mDigitTimeCalib) {
207281 getObjectsManager()->startPublishing(h);
208282 }
283+ */
209284
210285 getObjectsManager ()->startPublishing (histos.mDigitAmplitudeEMCAL );
211286 getObjectsManager ()->startPublishing (histos.mDigitAmplitudeDCAL );
0 commit comments