Project
Loading...
Searching...
No Matches
ITS3DigitizerSpec.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#include "ITSMFTDigitizerSpec.h"
18#include "Framework/Lifetime.h"
19#include "Framework/Task.h"
34#include "ITS3Base/ITS3Params.h"
35
36#include <TChain.h>
37#include <TStopwatch.h>
38
39#include <string>
40
41using namespace o2::framework;
43
44namespace o2::its3
45{
46using namespace o2::base;
48{
49 public:
51
52 ITS3DPLDigitizerTask(bool mctruth = true, bool doStag = false) : BaseDPLDigitizer(InitServices::FIELD | InitServices::GEOM), mWithMCTruth(mctruth), mDoStaggering(doStag) {}
53
55 {
56 mDisableQED = ic.options().get<bool>("disable-qed");
57 }
58
60 {
61 if (mFinished) {
62 return;
63 }
64 mFirstOrbitTF = pc.services().get<o2::framework::TimingInfo>().firstTForbit;
65 const o2::InteractionRecord firstIR(0, mFirstOrbitTF);
67
68 TStopwatch timer;
69 timer.Start();
70 LOG(info) << " CALLING ITS3 DIGITIZATION ";
71
72 // read collision context from input
73 auto context = pc.inputs().get<o2::steer::DigitizationContext*>("collisioncontext");
74 context->initSimChains(mID, mSimChains);
75 const bool withQED = context->isQEDProvided() && !mDisableQED;
76 auto& timesview = context->getEventRecords(withQED);
78 LOG(info) << "GOT " << timesview.size() << " COLLISSION TIMES";
79 LOG(info) << "SIMCHAINS " << mSimChains.size();
80
81 // if there is nothing to do ... return
82 if (timesview.empty()) {
83 return;
84 }
85
86 uint64_t nDigits{0};
87 for (uint32_t iLayer = 0; iLayer < (mDoStaggering ? 7 : 1); ++iLayer) {
88 const int layer = (mDoStaggering) ? iLayer : -1;
89 mDigitizer.setDigits(&mDigits[iLayer]);
90 mDigitizer.setROFRecords(&mROFRecords[iLayer]);
91 mDigitizer.setMCLabels(&mLabels[iLayer]);
92 mDigitizer.resetROFrameBounds();
93 // digits are directly put into DPL owned resource
94 auto& digitsAccum = pc.outputs().make<std::vector<itsmft::Digit>>(Output{mOrigin, "DIGITS", iLayer});
95
96 // rofs are accumulated first and the copied
97 const int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / par.getROFLengthInBC(iLayer);
98 const int nROFsTF = nROFsPerOrbit * raw::HBFUtils::Instance().getNOrbitsPerTF();
99 mROFRecordsAccum[iLayer].reserve(nROFsTF);
100
101 auto accumulate = [this, &digitsAccum, &iLayer]() {
102 // accumulate result of single event processing on a specific layer, called after processing every event supplied
103 // AND after the final flushing via digitizer::fillOutputContainer
104 if (!mDigits[iLayer].size()) {
105 return; // no digits were flushed, nothing to accumulate
106 }
107 auto ndigAcc = digitsAccum.size();
108 std::copy(mDigits[iLayer].begin(), mDigits[iLayer].end(), std::back_inserter(digitsAccum));
109
110 // fix ROFrecords references on ROF entries
111 auto nROFRecsOld = mROFRecordsAccum[iLayer].size();
112
113 for (int i = 0; i < mROFRecords[iLayer].size(); i++) {
114 auto& rof = mROFRecords[iLayer][i];
115 rof.setFirstEntry(ndigAcc + rof.getFirstEntry());
116 rof.print();
117 }
118
119 std::copy(mROFRecords[iLayer].begin(), mROFRecords[iLayer].end(), std::back_inserter(mROFRecordsAccum[iLayer]));
120 if (mWithMCTruth) {
121 mLabelsAccum[iLayer].mergeAtBack(mLabels[iLayer]);
122 }
123 LOG(info) << "Added " << mDigits[iLayer].size() << " digits" << ((mDoStaggering) ? std::format(" on layer {}", iLayer) : "");
124 // clean containers from already accumulated stuff
125 mLabels[iLayer].clear();
126 mDigits[iLayer].clear();
127 mROFRecords[iLayer].clear();
128 }; // and accumulate lambda
129
130 const auto& eventParts = context->getEventParts(withQED);
131 const int64_t bcShift = mDigitizer.getParams().getROFrameBiasInBC(layer); // this accounts the misalignment and the opt. imposed rof delay
132 // loop over all composite collisions given from context (aka loop over all the interaction records)
133 for (int collID = 0; collID < timesview.size(); ++collID) {
134 auto irt = timesview[collID];
135 if (irt.toLong() < bcShift) { // due to the ROF misalignment (+opt. delay) the collision would go to negative ROF ID, discard
136 continue;
137 }
138 irt -= bcShift; // account for the ROF start shift
139
140 mDigitizer.setEventTime(irt, layer);
141 mDigitizer.resetEventROFrames(); // to estimate min/max ROF for this collID
142 // for each collision, loop over the constituents event and source IDs
143 // (background signal merging is basically taking place here)
144 for (const auto& part : eventParts[collID]) {
145
146 // get the hits for this event and this source
147 mHits.clear();
148 context->retrieveHits(mSimChains, o2::detectors::SimTraits::DETECTORBRANCHNAMES[o2::detectors::DetID::IT3][0].c_str(), part.sourceID, part.entryID, &mHits);
149
150 if (mHits.size() > 0) {
151 LOG(debug) << "For collision " << collID << " eventID " << part.entryID << " found " << mHits.size() << " hits ";
152 mDigitizer.process(&mHits, part.entryID, part.sourceID, layer); // call actual digitization procedure
153 }
154 }
155 accumulate();
156 }
157 mDigitizer.fillOutputContainer(0xffffffff, layer);
158 accumulate();
159 nDigits += digitsAccum.size();
160
161 // here we have all digits and labels and we can send them to consumer (aka snapshot it onto output)
162 // ensure that the rof output is continuous
163 if (nROFsTF != mROFRecordsAccum[iLayer].size()) {
164 // it can happen that in the digitization rofs without contributing hits are skipped
165 // however downstream consumers of the clusters cannot know apriori the time structure
166 // the cluster rofs do not account for the bias so it will start always at BC=0
167 // also have to account for spillage into next TF
168 const size_t nROFsLayer = std::max((size_t)nROFsTF, mROFRecordsAccum[iLayer].size());
169 std::vector<o2::itsmft::ROFRecord> expDigitRofVec(nROFsLayer);
170 for (int iROF{0}; iROF < nROFsLayer; ++iROF) {
171 auto& rof = expDigitRofVec[iROF];
172 int orb = iROF * par.getROFLengthInBC(iLayer) / o2::constants::lhc::LHCMaxBunches + mFirstOrbitTF;
173 int bc = iROF * par.getROFLengthInBC(iLayer) % o2::constants::lhc::LHCMaxBunches + par.getROFDelayInBC(iLayer);
175 rof.setBCData(ir);
176 rof.setROFrame(iROF);
177 rof.setNEntries(0);
178 rof.setFirstEntry(-1);
179 }
180 uint32_t prevEntry{0};
181 for (const auto& rof : mROFRecordsAccum[iLayer]) {
182 const auto& ir = rof.getBCData();
183 if (ir < firstIR) {
184 LOGP(warn, "Discard ROF {} preceding TF 1st orbit {}{}", ir.asString(), mFirstOrbitTF, ((mDoStaggering) ? std::format(" on layer {}", iLayer) : ""));
185 continue;
186 }
187 auto irToFirst = ir - firstIR;
188 if (irToFirst.toLong() - par.getROFDelayInBC(iLayer) < 0) {
189 LOGP(warn, "Discard ROF {} preceding TF 1st orbit {} due to imposed ROF delay{}", ir.asString(), mFirstOrbitTF, ((mDoStaggering) ? std::format(" on layer {}", iLayer) : ""));
190 continue;
191 }
192 irToFirst -= par.getROFDelayInBC(iLayer);
193 const int irROF = irToFirst.toLong() / par.getROFLengthInBC(iLayer);
194 auto& expROF = expDigitRofVec[irROF];
195 expROF.setFirstEntry(rof.getFirstEntry());
196 expROF.setNEntries(rof.getNEntries());
197 if (expROF.getBCData() != rof.getBCData()) {
198 LOGP(fatal, "detected mismatch between expected {} and received {}", expROF.asString(), rof.asString());
199 }
200 }
201 int prevFirst{0};
202 for (auto& rof : expDigitRofVec) {
203 if (rof.getFirstEntry() < 0) {
204 rof.setFirstEntry(prevFirst);
205 }
206 prevFirst = rof.getFirstEntry();
207 }
208 // if more rofs where accumulated than ROFs possible in the TF, cut them away
209 // by construction expDigitRofVec is at least nROFsTF long
210 expDigitRofVec.resize(nROFsTF);
211 pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", iLayer}, expDigitRofVec);
212 } else {
213 pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", iLayer}, mROFRecordsAccum[iLayer]);
214 }
215 if (mWithMCTruth) {
216 auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{mOrigin, "DIGITSMCTR", iLayer});
217 mLabelsAccum[iLayer].flatten_to(sharedlabels);
218 // free space of existing label containers
219 mLabels[iLayer].clear_andfreememory();
220 mLabelsAccum[iLayer].clear_andfreememory();
221 }
222 }
223
224 LOG(info) << "IT3: Sending ROMode= " << mROMode << " to GRPUpdater";
225 pc.outputs().snapshot(Output{mOrigin, "ROMode", 0}, mROMode);
226
227 timer.Stop();
228 LOG(info) << "Digitization took " << timer.CpuTime() << "s";
229 LOG(info) << "Produced " << nDigits << " digits";
230
231 // we should be only called once; tell DPL that this process is ready to exit
232 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
233
234 mFinished = true;
235 }
236
238 {
239 static bool initOnce{false};
240 if (!initOnce) {
241 initOnce = true;
242 auto& digipar = mDigitizer.getParams();
243
244 // configure digitizer
246 geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)); // make sure L2G matrices are loaded
247 mDigitizer.setGeometry(geom);
248
250 const auto& doptIB = o2::its3::ITS3DPLDigitizerParam::Instance();
253 digipar.setContinuous(dopt.continuous);
254 digipar.setROFrameBiasInBC(aopt.roFrameBiasInBC);
255 if (dopt.continuous) {
257 digipar.setROFrameLengthInBC(aopt.roFrameLengthInBC);
258 digipar.setROFrameLength(frameNS); // RO frame in ns
259 digipar.setStrobeDelay(aopt.strobeDelay); // Strobe delay wrt beginning of the RO frame, in ns
260 digipar.setStrobeLength(aopt.strobeLengthCont > 0 ? aopt.strobeLengthCont : frameNS - aopt.strobeDelay); // Strobe length in ns
261 } else {
262 digipar.setROFrameLength(aopt.roFrameLengthTrig); // RO frame in ns
263 digipar.setStrobeDelay(aopt.strobeDelay); // Strobe delay wrt beginning of the RO frame, in ns
264 digipar.setStrobeLength(aopt.strobeLengthTrig); // Strobe length in ns
265 }
266 // parameters of signal time response: flat-top duration, max rise time and q @ which rise time is 0
267 digipar.getSignalShape().setParameters(dopt.strobeFlatTop, dopt.strobeMaxRiseTime, dopt.strobeQRiseTime0);
268 digipar.setChargeThreshold(dopt.chargeThreshold); // charge threshold in electrons
269 digipar.setNoisePerPixel(dopt.noisePerPixel); // noise level
270 digipar.setTimeOffset(dopt.timeOffset);
271 digipar.setNSimSteps(dopt.nSimSteps);
272
273 // ITS3 inner barrel specific parameters
274 digipar.setIBChargeThreshold(doptIB.IBChargeThreshold);
275 digipar.setIBNSimSteps(doptIB.nIBSimSteps);
276 digipar.setIBNoisePerPixel(doptIB.IBNoisePerPixel);
277
278 // staggering parameters
279 if (mDoStaggering) {
280 for (int iLayer{0}; iLayer < 7; ++iLayer) {
281 auto frameNS = aopt.getROFLengthInBC(iLayer) * o2::constants::lhc::LHCBunchSpacingNS;
282 digipar.addROFrameLayerLengthInBC(aopt.getROFLengthInBC(iLayer));
283 // NOTE: the rof delay looks from the digitizer like an additional bias
284 digipar.addROFrameLayerBiasInBC(aopt.getROFBiasInBC(iLayer) + aopt.getROFDelayInBC(iLayer));
285 digipar.addStrobeDelay(aopt.strobeDelay);
286 digipar.addStrobeLength(aopt.strobeLengthCont > 0 ? aopt.strobeLengthCont : frameNS - aopt.strobeDelay);
287 digipar.setROFrameLength(aopt.getROFLengthInBC(iLayer) * o2::constants::lhc::LHCBunchSpacingNS, iLayer);
288 }
289 }
290
292 LOG(info) << mID.getName() << " simulated in "
293 << ((mROMode == o2::parameters::GRPObject::CONTINUOUS) ? "CONTINUOUS" : "TRIGGERED")
294 << " RO mode";
295
296 if (o2::its3::ITS3Params::Instance().useDeadChannelMap) {
297 pc.inputs().get<o2::itsmft::NoiseMap*>("IT3_dead"); // trigger final ccdb update
298 }
299
300 pc.inputs().get<o2::itsmft::AlpideSimResponse*>("IT3_alpiderespvbb0");
301 if (o2::its3::ITS3Params::Instance().chipResponseFunction != "Alpide") {
302 pc.inputs().get<o2::itsmft::AlpideSimResponse*>("IT3_aptsresp");
303 }
304
305 // init digitizer
306 mDigitizer.init();
307 }
308 // Other time-dependent parameters can be added below
309 }
310
311 void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj)
312 {
313 if (matcher == ConcreteDataMatcher(detectors::DetID::ITS, "ALPIDEPARAM", 0)) {
314 LOG(info) << mID.getName() << " Alpide param updated";
316 par.printKeyValues();
317 return;
318 }
319 if (matcher == ConcreteDataMatcher(mOrigin, "DEADMAP", 0)) {
320 LOG(info) << mID.getName() << " static dead map updated";
322 return;
323 }
324 if (matcher == ConcreteDataMatcher(mOrigin, "ALPIDERESPVbb0", 0)) {
325 LOG(info) << mID.getName() << " loaded AlpideResponseData for Vbb=0V";
327 }
328 if (matcher == ConcreteDataMatcher(mOrigin, "APTSRESP", 0)) {
329 LOG(info) << mID.getName() << " loaded APTSResponseData";
331 }
332 }
333
334 private:
335 bool mWithMCTruth{true};
336 bool mFinished{false};
337 bool mDisableQED{false};
338 unsigned long mFirstOrbitTF = 0x0;
339 const o2::detectors::DetID mID{o2::detectors::DetID::IT3};
341 o2::its3::Digitizer mDigitizer{};
342 std::array<std::vector<o2::itsmft::Digit>, 7> mDigits{};
343 std::array<std::vector<o2::itsmft::ROFRecord>, 7> mROFRecords{};
344 std::array<std::vector<o2::itsmft::ROFRecord>, 7> mROFRecordsAccum{};
345 std::vector<o2::itsmft::Hit> mHits;
346 std::vector<o2::itsmft::Hit>* mHitsP{&mHits};
347 std::array<o2::dataformats::MCTruthContainer<o2::MCCompLabel>, 7> mLabels;
348 std::array<o2::dataformats::MCTruthContainer<o2::MCCompLabel>, 7> mLabelsAccum;
349 std::vector<TChain*> mSimChains{};
351 bool mDoStaggering = false;
352};
353
354namespace
355{
356std::vector<OutputSpec> makeOutChannels(o2::header::DataOrigin detOrig, bool mctruth, bool doStag)
357{
358 std::vector<OutputSpec> outputs;
359 for (int iLayer{0}; iLayer < (doStag ? 7 : 1); ++iLayer) {
360 outputs.emplace_back(detOrig, "DIGITS", iLayer, Lifetime::Timeframe);
361 outputs.emplace_back(detOrig, "DIGITSROF", iLayer, Lifetime::Timeframe);
362 if (mctruth) {
363 outputs.emplace_back(detOrig, "DIGITSMCTR", iLayer, Lifetime::Timeframe);
364 }
365 }
366 outputs.emplace_back(detOrig, "ROMode", 0, Lifetime::Timeframe);
367 return outputs;
368}
369} // namespace
370
371DataProcessorSpec getITS3DigitizerSpec(int channel, bool mctruth, bool doStag)
372{
373 auto detOrig = o2::header::gDataOriginIT3;
374 std::vector<InputSpec> inputs;
375 inputs.emplace_back("collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe);
376 inputs.emplace_back("ITS_alppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam"));
377 if (o2::its3::ITS3Params::Instance().useDeadChannelMap) {
378 inputs.emplace_back("IT3_dead", "IT3", "DEADMAP", 0, Lifetime::Condition, ccdbParamSpec("IT3/Calib/DeadMap"));
379 }
380 inputs.emplace_back("IT3_alpiderespvbb0", "IT3", "ALPIDERESPVbb0", 0, Lifetime::Condition, ccdbParamSpec("ITSMFT/Calib/ALPIDEResponseVbb0"));
381 inputs.emplace_back("IT3_aptsresp", "IT3", "APTSRESP", 0, Lifetime::Condition, ccdbParamSpec("IT3/Calib/APTSResponse"));
382
383 return DataProcessorSpec{.name = "IT3Digitizer",
384 .inputs = inputs,
385 .outputs = makeOutChannels(detOrig, mctruth, doStag),
386 .algorithm = AlgorithmSpec{adaptFromTask<ITS3DPLDigitizerTask>(mctruth)},
387 .options = Options{{"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}}}};
388}
389
390} // namespace o2::its3
Definition of the base digitizer task class.
A const (ready only) version of MCTruthContainer.
Definition of the ITSMFT digit.
o2::framework::DataAllocator::SubSpecificationType SubSpecificationType
std::ostringstream debug
uint64_t bc
Definition RawEventData.h:5
int32_t i
Header of the General Run Parameters object.
Definition of the GeometryTGeo class.
Definition of the ITSMFT ROFrame (trigger) record.
Definition of the ITS digitizer.
virtual void init(o2::framework::InitContext &) final
A read-only version of MCTruthContainer allowing for storage optimisation.
Static class with identifiers, bitmasks and names for ALICE detectors.
Definition DetID.h:58
static constexpr const char * getName(ID id)
names of defined detectors
Definition DetID.h:146
static constexpr ID ITS
Definition DetID.h:63
static const std::array< std::vector< std::string >, DetID::nDetectors > DETECTORBRANCHNAMES
Definition SimTraits.h:39
void snapshot(const Output &spec, T const &object)
o2::header::DataHeader::SubSpecificationType SubSpecificationType
decltype(auto) make(const Output &spec, Args... args)
ConfigParamRegistry const & options()
Definition InitContext.h:33
decltype(auto) get(R binding, int part=0) const
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
void setOBSimResponse(const o2::itsmft::AlpideSimResponse *response)
Definition DigiParams.h:49
void setIBSimResponse(const o2::itsmft::AlpideSimResponse *resp)
void fillOutputContainer(uint32_t maxFrame=0xffffffff, int layer=-1)
void setDeadChannelsMap(const o2::itsmft::NoiseMap *mp)
Definition Digitizer.h:86
void setROFRecords(std::vector< o2::itsmft::ROFRecord > *rec)
Definition Digitizer.h:49
void setDigits(std::vector< o2::itsmft::Digit > *dig)
Definition Digitizer.h:47
void setGeometry(const o2::its::GeometryTGeo *gm)
Definition Digitizer.h:70
o2::its3::DigiParams & getParams()
Definition Digitizer.h:51
void resetROFrameBounds()
Definition Digitizer.h:79
void resetEventROFrames()
Definition Digitizer.h:74
void process(const std::vector< itsmft::Hit > *hits, int evID, int srcID, int layer)
Steer conversion of hits to digits.
Definition Digitizer.cxx:76
void setMCLabels(o2::dataformats::MCTruthContainer< o2::MCCompLabel > *mclb)
Definition Digitizer.h:48
void setEventTime(const o2::InteractionTimeRecord &irt, int layer)
ITS3DPLDigitizerTask(bool mctruth=true, bool doStag=false)
void run(framework::ProcessingContext &pc)
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj)
void initDigitizerTask(framework::InitContext &ic) override
void updateTimeDependentParams(ProcessingContext &pc)
static GeometryTGeo * Instance()
void fillMatrixCache(int mask) override
int getROFrameBiasInBC(int layer=-1) const
Definition DigiParams.h:73
NoiseMap class for the ITS and MFT.
Definition NoiseMap.h:39
bool initSimChains(o2::detectors::DetID detid, std::vector< TChain * > &simchains) const
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
constexpr o2::header::DataOrigin gDataOriginIT3
Definition DataHeader.h:582
constexpr int LHCMaxBunches
constexpr double LHCBunchSpacingNS
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
std::vector< ConfigParamSpec > ccdbParamSpec(std::string const &path, int runDependent, std::vector< CCDBMetadata > metadata={}, int qrate=0)
std::vector< ConfigParamSpec > Options
header::DataHeader::SubSpecificationType SubSpecificationType
DataProcessorSpec getITS3DigitizerSpec(int channel, bool mctruth, bool doStag)
std::string asString() const
class listing possible services
int roFrameBiasInBC
bias of the start of ROF wrt orbit start: t_irof = (irof*roFrameLengthInBC + roFrameBiasInBC)*BClengt...
float strobeDelay
strobe start (in ns) wrt ROF start
int getROFLengthInBC(int layer) const noexcept
int roFrameLengthInBC
ROF length in BC for continuous mode.
float strobeLengthCont
if < 0, full ROF length - delay
int getROFDelayInBC(int layer) const noexcept
float strobeLengthTrig
length of the strobe in ns (sig. over threshold checked in this window only)
float roFrameLengthTrig
length of RO frame in ns for triggered mode
int getROFBiasInBC(int layer) const noexcept
static constexpr int L2G
Definition Cartesian.h:54
int getNOrbitsPerTF() const
get IR corresponding to start of the HBF
Definition HBFUtils.h:49
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)