Skip to content

Commit 0304e7c

Browse files
committed
[EMCAL-704] Add suport of cell container in multiple subtimeframes
In case the reconstruction runs on the FLP the cells might come from two different cell containers from the two subtimeframes. In this case the cell containers might not be merged, but instead the TriggerRecords are merged to have two different RangeReferences with a subspecification, called Subevent. The event loop iterates over the CombinedEvent containing the interaction record, the trigger type and the list of subevents. In order to identify the cell container based on the subspecification a map is built at the beginning of the monitorData function.
1 parent ef1655d commit 0304e7c

2 files changed

Lines changed: 141 additions & 44 deletions

File tree

Modules/EMCAL/include/EMCAL/DigitsQcTask.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@
1919

2020
#include "QualityControl/TaskInterface.h"
2121
#include <array>
22+
#include <gsl/span>
2223
#include <CCDB/TObjectWrapper.h>
2324
#include <TProfile2D.h>
25+
#include "CommonDataFormat/InteractionRecord.h"
26+
#include "CommonDataFormat/RangeReference.h"
27+
#include "DataFormatsEMCAL/TriggerRecord.h"
2428

2529
class TH1;
2630
class TH2;
@@ -89,6 +93,24 @@ class DigitsQcTask final : public TaskInterface
8993
void setEndOfPayloadCheck(Bool_t doCheck) { mDoEndOfPayloadCheck = doCheck; }
9094

9195
private:
96+
struct SubEvent {
97+
int mSpecification;
98+
dataformats::RangeReference<int, int> mCellRange;
99+
};
100+
struct CombinedEvent {
101+
InteractionRecord mInteractionRecord;
102+
uint32_t mTriggerType;
103+
std::vector<SubEvent> mSubevents;
104+
105+
int getNumberOfObjects() const
106+
{
107+
int nObjects = 0;
108+
for (auto ev : mSubevents)
109+
nObjects += ev.mCellRange.getEntries();
110+
return 0;
111+
}
112+
};
113+
std::vector<CombinedEvent> buildCombinedEvents(const std::map<int, gsl::span<const o2::emcal::TriggerRecord>>& triggerrecords) const;
92114
void startPublishing(DigitsHistograms& histos);
93115
Double_t mCellThreshold = 0.5; ///< energy cell threshold
94116
Bool_t mDoEndOfPayloadCheck = false; ///< Do old style end-of-payload check

Modules/EMCAL/src/DigitsQcTask.cxx

Lines changed: 119 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@
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

3337
namespace 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+
193265
void 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

Comments
 (0)