Project
Loading...
Searching...
No Matches
TRKDigitizerSpec.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 "TRKDigitizerSpec.h"
18#include "Framework/Lifetime.h"
19#include "Framework/Task.h"
31#include "TRKBase/AlmiraParam.h"
33#include "TRKBase/Specs.h"
35
36#include <TChain.h>
37#include <TStopwatch.h>
38
39#include <algorithm>
40#include <memory>
41#include <string>
42
43using namespace o2::framework;
45
46namespace
47{
48std::vector<OutputSpec> makeOutChannels(o2::header::DataOrigin detOrig, bool mctruth)
49{
50 std::vector<OutputSpec> outputs;
51 for (uint32_t iLayer = 0; iLayer < o2::trk::AlmiraParam::getNLayers(); ++iLayer) {
52 outputs.emplace_back(detOrig, "DIGITS", iLayer, Lifetime::Timeframe);
53 outputs.emplace_back(detOrig, "DIGITSROF", iLayer, Lifetime::Timeframe);
54 if (mctruth) {
55 outputs.emplace_back(detOrig, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe);
56 outputs.emplace_back(detOrig, "DIGITSMCTR", iLayer, Lifetime::Timeframe);
57 }
58 }
59 outputs.emplace_back(detOrig, "ROMode", 0, Lifetime::Timeframe);
60 return outputs;
61}
62} // namespace
63
64namespace o2::trk
65{
66using namespace o2::base;
68{
69 public:
71
72 TRKDPLDigitizerTask(bool mctruth = true) : BaseDPLDigitizer(InitServices::FIELD | InitServices::GEOM), mWithMCTruth(mctruth) {}
73
75 {
76 mDisableQED = ic.options().get<bool>("disable-qed");
77 mLocalRespFile = ic.options().get<std::string>("local-response-file");
78 }
79
81 {
82 if (mFinished) {
83 return;
84 }
85 mFirstOrbitTF = pc.services().get<o2::framework::TimingInfo>().firstTForbit;
86 const o2::InteractionRecord firstIR(0, mFirstOrbitTF);
88
89 // read collision context from input
90 auto context = pc.inputs().get<o2::steer::DigitizationContext*>("collisioncontext");
91 context->initSimChains(mID, mSimChains);
92 const bool withQED = context->isQEDProvided() && !mDisableQED;
93 auto& timesview = context->getEventRecords(withQED);
94 LOG(info) << "GOT " << timesview.size() << " COLLISION TIMES";
95 LOG(info) << "SIMCHAINS " << mSimChains.size();
96
97 // if there is nothing to do ... return
98 if (timesview.empty()) {
99 return;
100 }
101 TStopwatch timer;
102 timer.Start();
103 LOG(info) << " CALLING TRK DIGITIZATION ";
104
105 auto& eventParts = context->getEventParts(withQED);
106 uint64_t nDigits{0};
107 for (uint32_t iLayer = 0; iLayer < static_cast<uint32_t>(mLayers); ++iLayer) {
108 mDigits[iLayer].clear();
109 mROFRecords[iLayer].clear();
110 mROFRecordsAccum[iLayer].clear();
111 if (mWithMCTruth) {
112 mLabels[iLayer].clear();
113 mLabelsAccum[iLayer].clear();
114 mMC2ROFRecordsAccum[iLayer].clear();
115 }
116
117 mDigitizer.setDigits(&mDigits[iLayer]);
118 mDigitizer.setROFRecords(&mROFRecords[iLayer]);
119 mDigitizer.setMCLabels(&mLabels[iLayer]);
120 mDigitizer.resetROFrameBounds();
121
122 // digits are directly put into DPL owned resource
123 auto& digitsAccum = pc.outputs().make<std::vector<itsmft::Digit>>(Output{mOrigin, "DIGITS", iLayer});
124
125 const int roFrameLengthInBC = mDigitizer.getParams().getROFrameLengthInBC(iLayer);
126 const int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / roFrameLengthInBC;
127 const int nROFsTF = nROFsPerOrbit * raw::HBFUtils::Instance().getNOrbitsPerTF();
128 mROFRecordsAccum[iLayer].reserve(nROFsTF);
129
130 auto accumulate = [this, &digitsAccum, &iLayer]() {
131 // accumulate result of single event processing on one layer, called after each collision
132 // and after the final flushing via digitizer::fillOutputContainer
133 if (mDigits[iLayer].empty()) {
134 return;
135 }
136 auto ndigAcc = digitsAccum.size();
137 std::copy(mDigits[iLayer].begin(), mDigits[iLayer].end(), std::back_inserter(digitsAccum));
138
139 for (auto& rof : mROFRecords[iLayer]) {
140 rof.setFirstEntry(ndigAcc + rof.getFirstEntry());
141 }
142
143 std::copy(mROFRecords[iLayer].begin(), mROFRecords[iLayer].end(), std::back_inserter(mROFRecordsAccum[iLayer]));
144 if (mWithMCTruth) {
145 mLabelsAccum[iLayer].mergeAtBack(mLabels[iLayer]);
146 }
147 LOG(info) << "Added " << mDigits[iLayer].size() << " digits on layer " << iLayer;
148 mLabels[iLayer].clear();
149 mDigits[iLayer].clear();
150 mROFRecords[iLayer].clear();
151 };
152
153 const int bcShift = mDigitizer.getParams().getROFrameBiasInBC(iLayer);
154 for (size_t collID = 0; collID < timesview.size(); ++collID) {
155 auto irt = timesview[collID];
156 if (irt.toLong() < bcShift) {
157 continue;
158 }
159 irt -= bcShift;
160
161 mDigitizer.setEventTime(irt, iLayer);
162 mDigitizer.resetEventROFrames();
163 for (auto& part : eventParts[collID]) {
164 mHits.clear();
165 context->retrieveHits(mSimChains, o2::detectors::SimTraits::DETECTORBRANCHNAMES[mID][0].c_str(), part.sourceID, part.entryID, &mHits);
166
167 if (!mHits.empty()) {
168 LOG(debug) << "For collision " << collID << " eventID " << part.entryID
169 << " found " << mHits.size() << " hits on layer " << iLayer;
170 mDigitizer.process(&mHits, part.entryID, part.sourceID, iLayer);
171 }
172 }
173 if (mWithMCTruth) {
174 mMC2ROFRecordsAccum[iLayer].emplace_back(collID, -1, mDigitizer.getEventROFrameMin(), mDigitizer.getEventROFrameMax());
175 }
176 accumulate();
177 }
178 mDigitizer.fillOutputContainer(0xffffffff, iLayer);
179 accumulate();
180 nDigits += digitsAccum.size();
181
182 std::vector<o2::itsmft::ROFRecord> expDigitRofVec(nROFsTF);
183 for (int iROF = 0; iROF < nROFsTF; ++iROF) {
184 auto& rof = expDigitRofVec[iROF];
185 const int orb = iROF * roFrameLengthInBC / o2::constants::lhc::LHCMaxBunches + mFirstOrbitTF;
186 const int bc = iROF * roFrameLengthInBC % o2::constants::lhc::LHCMaxBunches;
187 rof.setBCData(o2::InteractionRecord(bc, orb));
188 rof.setROFrame(iROF);
189 rof.setNEntries(0);
190 rof.setFirstEntry(-1);
191 }
192
193 for (const auto& rof : mROFRecordsAccum[iLayer]) {
194 const auto& ir = rof.getBCData();
195 const auto irToFirst = ir - firstIR;
196 const auto irROF = irToFirst.toLong() / roFrameLengthInBC;
197 if (irROF < 0 || irROF >= nROFsTF) {
198 continue;
199 }
200 auto& expROF = expDigitRofVec[irROF];
201 expROF.setFirstEntry(rof.getFirstEntry());
202 expROF.setNEntries(rof.getNEntries());
203 if (expROF.getBCData() != rof.getBCData()) {
204 LOGP(fatal, "detected mismatch between expected {} and received {}", expROF.asString(), rof.asString());
205 }
206 }
207
208 int prevFirst = 0;
209 for (auto& rof : expDigitRofVec) {
210 if (rof.getFirstEntry() < 0) {
211 rof.setFirstEntry(prevFirst);
212 }
213 prevFirst = rof.getFirstEntry();
214 }
215
216 pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", iLayer}, expDigitRofVec);
217 if (mWithMCTruth) {
218 std::vector<o2::itsmft::MC2ROFRecord> clippedMC2ROFRecords;
219 clippedMC2ROFRecords.reserve(mMC2ROFRecordsAccum[iLayer].size());
220 for (auto mc2rof : mMC2ROFRecordsAccum[iLayer]) {
221 if (mc2rof.minROF >= static_cast<uint32_t>(nROFsTF) || mc2rof.minROF > mc2rof.maxROF) {
222 mc2rof.rofRecordID = -1;
223 mc2rof.minROF = 0;
224 mc2rof.maxROF = 0;
225 } else {
226 mc2rof.maxROF = std::min<uint32_t>(mc2rof.maxROF, nROFsTF - 1);
227 if (mc2rof.minROF > mc2rof.maxROF) {
228 mc2rof.rofRecordID = -1;
229 mc2rof.minROF = 0;
230 mc2rof.maxROF = 0;
231 } else {
232 mc2rof.rofRecordID = mc2rof.minROF;
233 }
234 }
235 clippedMC2ROFRecords.push_back(mc2rof);
236 }
237 pc.outputs().snapshot(Output{mOrigin, "DIGITSMC2ROF", iLayer}, clippedMC2ROFRecords);
238 auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{mOrigin, "DIGITSMCTR", iLayer});
239 mLabelsAccum[iLayer].flatten_to(sharedlabels);
240 mLabels[iLayer].clear_andfreememory();
241 mLabelsAccum[iLayer].clear_andfreememory();
242 }
243 }
244 LOG(info) << mID.getName() << ": Sending ROMode= " << mROMode << " to GRPUpdater";
245 pc.outputs().snapshot(Output{mOrigin, "ROMode", 0}, mROMode);
246
247 timer.Stop();
248 LOG(info) << "Digitization took " << timer.CpuTime() << "s";
249 LOG(info) << "Produced " << nDigits << " digits";
250
251 // we should be only called once; tell DPL that this process is ready to exit
252 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
253
254 mFinished = true;
255 }
256
258 {
259 std::unique_ptr<TFile> file(TFile::Open(mLocalRespFile.data(), "READ"));
260 if (!file) {
261 LOG(fatal) << "Cannot open response file " << mLocalRespFile;
262 }
263 mDigitizer.getParams().setResponse((const o2::itsmft::AlpideSimResponse*)file->Get("response1"));
264 }
265
267 {
268 static bool initOnce{false};
269 if (!initOnce) {
270 initOnce = true;
271 auto& digipar = mDigitizer.getParams();
272
273 // configure digitizer
275 geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)); // make sure L2G matrices are loaded
276 geom->Print();
277 mDigitizer.setGeometry(geom);
278
280 // pc.inputs().get<o2::trk::AlmiraParam*>("TRK_almiraparam");
281 const auto& aopt = o2::trk::AlmiraParam::Instance();
283 mDigits.resize(mLayers);
284 mROFRecords.resize(mLayers);
285 mROFRecordsAccum.resize(mLayers);
286 mLabels.resize(mLayers);
287 mLabelsAccum.resize(mLayers);
288 mMC2ROFRecordsAccum.resize(mLayers);
289
290 for (int iLayer = 0; iLayer < mLayers; ++iLayer) {
291 const auto roFrameLengthInBC = aopt.getROFLengthInBC(iLayer);
292 const auto frameNS = roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS;
293 digipar.setROFrameLengthInBC(roFrameLengthInBC, iLayer);
294 // ROF delay is treated as an additional bias from the digitizer point of view.
295 digipar.setROFrameBiasInBC(aopt.getROFBiasInBC(iLayer) + aopt.getROFDelayInBC(iLayer), iLayer);
296 digipar.setStrobeDelay(aopt.getStrobeDelay(iLayer), iLayer);
297 const auto strobeLengthCont = aopt.getStrobeLengthCont(iLayer);
298 digipar.setStrobeLength(strobeLengthCont > 0 ? strobeLengthCont : frameNS - aopt.getStrobeDelay(iLayer), iLayer);
299 digipar.setROFrameLength(frameNS, iLayer);
300 }
301 // parameters of signal time response: flat-top duration, max rise time and q @ which rise time is 0
302 digipar.getSignalShape().setParameters(dopt.strobeFlatTop, dopt.strobeMaxRiseTime, dopt.strobeQRiseTime0);
303 digipar.setChargeThreshold(dopt.chargeThreshold); // charge threshold in electrons
304 digipar.setNoisePerPixel(dopt.noisePerPixel); // noise level
305 digipar.setTimeOffset(dopt.timeOffset);
306 digipar.setNSimSteps(dopt.nSimSteps);
307
309 LOG(info) << mID.getName() << " simulated in CONTINUOUS RO mode";
310
311 // if (oTRKParams::Instance().useDeadChannelMap) {
312 // pc.inputs().get<o2::itsmft::NoiseMap*>("TRK_dead"); // trigger final ccdb update
313 // }
314 pc.inputs().get<o2::itsmft::AlpideSimResponse*>("TRK_aptsresp");
315
316 // init digitizer
317 mDigitizer.init();
318 }
319 // Other time-dependent parameters can be added below
320 }
321
322 void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj)
323 {
324 if (matcher == ConcreteDataMatcher(mOrigin, "ALMIRAPARAM", 0)) {
325 LOG(info) << mID.getName() << " Almira param updated";
326 const auto& par = o2::trk::AlmiraParam::Instance();
327 par.printKeyValues();
328 return;
329 }
330 // if (matcher == ConcreteDataMatcher(mOrigin, "DEADMAP", 0)) {
331 // LOG(info) << mID.getName() << " static dead map updated";
332 // mDigitizer.setDeadChannelsMap((o2::itsmft::NoiseMap*)obj);
333 // return;
334 // }
335 if (matcher == ConcreteDataMatcher(mOrigin, "APTSRESP", 0)) {
336 LOG(info) << mID.getName() << " loaded APTSResponseData";
337 if (mLocalRespFile.empty()) {
338 LOG(info) << "Using CCDB/APTS response file";
339 mDigitizer.getParams().setResponse((const o2::itsmft::AlpideSimResponse*)obj);
340 mDigitizer.setResponseName("APTS");
341 } else {
342 LOG(info) << "Response function will be loaded from local file: " << mLocalRespFile;
344 mDigitizer.setResponseName("ALICE3");
345 }
346 }
347 }
348
349 private:
350 bool mWithMCTruth{true};
351 bool mFinished{false};
352 bool mDisableQED{false};
353 unsigned long mFirstOrbitTF = 0x0;
354 std::string mLocalRespFile{""};
355 const o2::detectors::DetID mID{o2::detectors::DetID::TRK};
357 o2::trk::Digitizer mDigitizer{};
358 int mLayers{0};
359 std::vector<std::vector<o2::itsmft::Digit>> mDigits{};
360 std::vector<std::vector<o2::itsmft::ROFRecord>> mROFRecords{};
361 std::vector<std::vector<o2::itsmft::ROFRecord>> mROFRecordsAccum{};
362 std::vector<o2::trk::Hit> mHits{};
363 std::vector<o2::trk::Hit>* mHitsP{&mHits};
364 std::vector<o2::dataformats::MCTruthContainer<o2::MCCompLabel>> mLabels{};
365 std::vector<o2::dataformats::MCTruthContainer<o2::MCCompLabel>> mLabelsAccum{};
366 std::vector<std::vector<o2::itsmft::MC2ROFRecord>> mMC2ROFRecordsAccum{};
367 std::vector<TChain*> mSimChains{};
369};
370
371DataProcessorSpec getTRKDigitizerSpec(int channel, bool mctruth)
372{
373 std::string detStr = o2::detectors::DetID::getName(o2::detectors::DetID::TRK);
374 auto detOrig = o2::header::gDataOriginTRK;
375 std::vector<InputSpec> inputs;
376 inputs.emplace_back("collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe);
377 // inputs.emplace_back("TRK_almiraparam", "TRK", "ALMIRAPARAM", 0, Lifetime::Condition, ccdbParamSpec("TRK/Config/AlmiraParam"));
378 // if (oTRKParams::Instance().useDeadChannelMap) {
379 // inputs.emplace_back("TRK_dead", "TRK", "DEADMAP", 0, Lifetime::Condition, ccdbParamSpec("TRK/Calib/DeadMap"));
380 // }
381 inputs.emplace_back("TRK_aptsresp", "TRK", "APTSRESP", 0, Lifetime::Condition, ccdbParamSpec("IT3/Calib/APTSResponse"));
382
383 return DataProcessorSpec{detStr + "Digitizer",
384 inputs, makeOutChannels(detOrig, mctruth),
385 AlgorithmSpec{adaptFromTask<TRKDPLDigitizerTask>(mctruth)},
386 Options{
387 {"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}},
388 {"local-response-file", o2::framework::VariantType::String, "", {"use response file saved locally at this path/filename"}}}};
389}
390
391} // namespace o2::trk
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
Header of the General Run Parameters object.
Definition of the ITSMFT ROFrame (trigger) record.
specs of the ALICE3 TRK
Definition of the TRK 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 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.
bool initSimChains(o2::detectors::DetID detid, std::vector< TChain * > &simchains) const
int getROFrameBiasInBC(int layer) const
Definition DigiParams.h:73
void setResponse(const o2::itsmft::AlpideSimResponse *)
int getROFrameLengthInBC(int layer) const
Definition DigiParams.h:56
o2::trk::DigiParams & getParams()
Definition Digitizer.h:50
void setResponseName(const std::string &name)
Definition Digitizer.h:48
void setEventTime(const o2::InteractionTimeRecord &irt, int layer)
uint32_t getEventROFrameMin() const
Definition Digitizer.h:77
void process(const std::vector< o2::trk::Hit > *hits, int evID, int srcID, int layer)
Steer conversion of hits to digits.
void setDigits(std::vector< o2::itsmft::Digit > *dig)
Definition Digitizer.h:45
void setROFRecords(std::vector< o2::itsmft::ROFRecord > *rec)
Definition Digitizer.h:47
void setMCLabels(o2::dataformats::MCTruthContainer< o2::MCCompLabel > *mclb)
Definition Digitizer.h:46
void fillOutputContainer(uint32_t maxFrame, int layer)
void resetROFrameBounds()
Definition Digitizer.h:63
void setGeometry(const o2::trk::GeometryTGeo *gm)
Definition Digitizer.h:75
uint32_t getEventROFrameMax() const
Definition Digitizer.h:78
void resetEventROFrames()
Definition Digitizer.h:79
void Print(Option_t *opt="") const
void fillMatrixCache(int mask)
int getNumberOfLayersMLOT() const
static GeometryTGeo * Instance()
TRKDPLDigitizerTask(bool mctruth=true)
void run(framework::ProcessingContext &pc)
void updateTimeDependentParams(ProcessingContext &pc)
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj)
void initDigitizerTask(framework::InitContext &ic) override
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
constexpr o2::header::DataOrigin gDataOriginTRK
Definition DataHeader.h:584
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
constexpr int nLayers
Definition Specs.h:45
DataProcessorSpec getTRKDigitizerSpec(int channel, bool mctruth)
void empty(int)
class listing possible services
static constexpr int L2G
Definition Cartesian.h:54
int getNOrbitsPerTF() const
get IR corresponding to start of the HBF
Definition HBFUtils.h:49
static constexpr size_t getNLayers()
Definition AlmiraParam.h:29
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)