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"
33#include "TRKBase/AlmiraParam.h"
35#include "TRKBase/Specs.h"
37
38#include <TChain.h>
39#include <TStopwatch.h>
40
41#include <algorithm>
42#include <memory>
43#include <string>
44
45using namespace o2::framework;
47
48namespace
49{
50std::vector<OutputSpec> makeOutChannels(o2::header::DataOrigin detOrig, int nLayers, bool mctruth)
51{
52 std::vector<OutputSpec> outputs;
53 for (uint32_t iLayer = 0; iLayer < static_cast<uint32_t>(nLayers); ++iLayer) {
54 outputs.emplace_back(detOrig, "DIGITS", iLayer, Lifetime::Timeframe);
55 outputs.emplace_back(detOrig, "DIGITSROF", iLayer, Lifetime::Timeframe);
56 if (mctruth) {
57 outputs.emplace_back(detOrig, "DIGITSMCTR", iLayer, Lifetime::Timeframe);
58 }
59 }
60 outputs.emplace_back(detOrig, "ROMode", 0, Lifetime::Timeframe);
61 return outputs;
62}
63} // namespace
64
65namespace o2::trkft3
66{
67using namespace o2::base;
68
69template <int N>
71{
72 if constexpr (N == o2::detectors::DetID::TRK) {
74 } else {
76 }
77}
78
79template <int N>
81{
82 public:
83 static_assert(N == o2::detectors::DetID::TRK || N == o2::detectors::DetID::FT3, "only TRK and FT3 digitizers are supported");
84 static constexpr o2::detectors::DetID ID{N == o2::detectors::DetID::TRK ? o2::detectors::DetID::TRK : o2::detectors::DetID::FT3};
85 static constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::TRK ? o2::header::gDataOriginTRK : o2::header::gDataOriginFT3};
87
88 TRKFT3DPLDigitizerTask(bool mctruth = true) : BaseDPLDigitizer(InitServices::FIELD | InitServices::GEOM), mWithMCTruth(mctruth) {}
89
91 {
92 mDisableQED = ic.options().get<bool>("disable-qed");
93 mLocalRespFile = ic.options().get<std::string>("local-response-file");
94 }
95
97 {
98 if (mFinished) {
99 return;
100 }
101 mFirstOrbitTF = pc.services().get<o2::framework::TimingInfo>().firstTForbit;
102 const o2::InteractionRecord firstIR(0, mFirstOrbitTF);
104
105 // read collision context from input
106 auto context = pc.inputs().get<o2::steer::DigitizationContext*>("collisioncontext");
107 context->initSimChains(ID, mSimChains);
108 const bool withQED = context->isQEDProvided() && !mDisableQED;
109 auto& timesview = context->getEventRecords(withQED);
110 LOG(info) << "GOT " << timesview.size() << " COLLISION TIMES";
111 LOG(info) << "SIMCHAINS " << mSimChains.size();
112
113 // if there is nothing to do ... return
114 if (timesview.empty()) {
115 return;
116 }
117 TStopwatch timer;
118 timer.Start();
119 LOG(info) << " CALLING " << ID.getName() << " DIGITIZATION ";
120
121 auto& eventParts = context->getEventParts(withQED);
122 uint64_t nDigits{0};
123 for (uint32_t iLayer = 0; iLayer < static_cast<uint32_t>(mLayers); ++iLayer) {
124 mDigits[iLayer].clear();
125 mROFRecords[iLayer].clear();
126 mROFRecordsAccum[iLayer].clear();
127 if (mWithMCTruth) {
128 mLabels[iLayer].clear();
129 mLabelsAccum[iLayer].clear();
130 }
131
132 mDigitizer.setDigits(&mDigits[iLayer]);
133 mDigitizer.setROFRecords(&mROFRecords[iLayer]);
134 mDigitizer.setMCLabels(&mLabels[iLayer]);
135 mDigitizer.resetROFrameBounds();
136
137 // digits are directly put into DPL owned resource
138 auto& digitsAccum = pc.outputs().make<std::vector<trkft3::Digit>>(Output{Origin, "DIGITS", iLayer});
139
140 const int roFrameLengthInBC = mDigitizer.getParams().getROFrameLengthInBC(iLayer);
141 const int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / roFrameLengthInBC;
142 const int nROFsTF = nROFsPerOrbit * raw::HBFUtils::Instance().getNOrbitsPerTF();
143 mROFRecordsAccum[iLayer].reserve(nROFsTF);
144
145 auto accumulate = [this, &digitsAccum, &iLayer]() {
146 // accumulate result of single event processing on one layer, called after each collision
147 // and after the final flushing via digitizer::fillOutputContainer
148 if (mDigits[iLayer].empty()) {
149 return;
150 }
151 auto ndigAcc = digitsAccum.size();
152 std::copy(mDigits[iLayer].begin(), mDigits[iLayer].end(), std::back_inserter(digitsAccum));
153
154 for (auto& rof : mROFRecords[iLayer]) {
155 rof.setFirstEntry(ndigAcc + rof.getFirstEntry());
156 }
157
158 std::copy(mROFRecords[iLayer].begin(), mROFRecords[iLayer].end(), std::back_inserter(mROFRecordsAccum[iLayer]));
159 if (mWithMCTruth) {
160 mLabelsAccum[iLayer].mergeAtBack(mLabels[iLayer]);
161 }
162 LOG(info) << "Added " << mDigits[iLayer].size() << " digits on layer " << iLayer;
163 mLabels[iLayer].clear();
164 mDigits[iLayer].clear();
165 mROFRecords[iLayer].clear();
166 };
167
168 const int bcShift = mDigitizer.getParams().getROFrameBiasInBC(iLayer);
169 for (size_t collID = 0; collID < timesview.size(); ++collID) {
170 auto irt = timesview[collID];
171 if (irt.toLong() < bcShift) {
172 continue;
173 }
174 irt -= bcShift;
175
176 mDigitizer.setEventTime(irt, iLayer);
177 mDigitizer.resetEventROFrames();
178 for (auto& part : eventParts[collID]) {
179 mHits.clear();
180 context->retrieveHits(mSimChains, o2::detectors::SimTraits::DETECTORBRANCHNAMES[ID][0].c_str(), part.sourceID, part.entryID, &mHits);
181
182 if (!mHits.empty()) {
183 LOG(debug) << "For collision " << collID << " eventID " << part.entryID
184 << " found " << mHits.size() << " hits on layer " << iLayer;
185 mDigitizer.process(&mHits, part.entryID, part.sourceID, iLayer);
186 }
187 }
188 accumulate();
189 }
190 mDigitizer.fillOutputContainer(0xffffffff, iLayer);
191 accumulate();
192 nDigits += digitsAccum.size();
193
194 std::vector<o2::trkft3::ROFRecord> expDigitRofVec(nROFsTF);
195 for (int iROF = 0; iROF < nROFsTF; ++iROF) {
196 auto& rof = expDigitRofVec[iROF];
197 const int orb = iROF * roFrameLengthInBC / o2::constants::lhc::LHCMaxBunches + mFirstOrbitTF;
198 const int bc = iROF * roFrameLengthInBC % o2::constants::lhc::LHCMaxBunches;
199 rof.setBCData(o2::InteractionRecord(bc, orb));
200 rof.setROFrame(iROF);
201 rof.setNEntries(0);
202 rof.setFirstEntry(-1);
203 }
204
205 for (const auto& rof : mROFRecordsAccum[iLayer]) {
206 const auto& ir = rof.getBCData();
207 const auto irToFirst = ir - firstIR;
208 const auto irROF = irToFirst.toLong() / roFrameLengthInBC;
209 if (irROF < 0 || irROF >= nROFsTF) {
210 continue;
211 }
212 auto& expROF = expDigitRofVec[irROF];
213 expROF.setFirstEntry(rof.getFirstEntry());
214 expROF.setNEntries(rof.getNEntries());
215 if (expROF.getBCData() != rof.getBCData()) {
216 LOGP(fatal, "detected mismatch between expected {} and received {}", expROF.asString(), rof.asString());
217 }
218 }
219
220 int prevFirst = 0;
221 for (auto& rof : expDigitRofVec) {
222 if (rof.getFirstEntry() < 0) {
223 rof.setFirstEntry(prevFirst);
224 }
225 prevFirst = rof.getFirstEntry();
226 }
227
228 pc.outputs().snapshot(Output{Origin, "DIGITSROF", iLayer}, expDigitRofVec);
229 if (mWithMCTruth) {
230 auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{Origin, "DIGITSMCTR", iLayer});
231 mLabelsAccum[iLayer].flatten_to(sharedlabels);
232 mLabels[iLayer].clear_andfreememory();
233 mLabelsAccum[iLayer].clear_andfreememory();
234 }
235 }
236 LOG(info) << ID.getName() << ": Sending ROMode= " << mROMode << " to GRPUpdater";
237 pc.outputs().snapshot(Output{Origin, "ROMode", 0}, mROMode);
238
239 timer.Stop();
240 LOG(info) << "Digitization took " << timer.CpuTime() << "s";
241 LOG(info) << "Produced " << nDigits << " digits";
242
243 // we should be only called once; tell DPL that this process is ready to exit
244 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
245
246 mFinished = true;
247 }
248
250 {
251 std::unique_ptr<TFile> file(TFile::Open(mLocalRespFile.data(), "READ"));
252 if (!file) {
253 LOG(fatal) << "Cannot open response file " << mLocalRespFile;
254 }
255 mDigitizer.getParams().setResponse((const o2::itsmft::AlpideSimResponse*)file->Get("response1"));
256 }
257
259 {
260 static bool initOnce{false};
261 if (!initOnce) {
262 initOnce = true;
263 auto& digipar = mDigitizer.getParams();
264
266 const auto& aopt = o2::trk::AlmiraParam::Instance();
267 if constexpr (N == o2::detectors::DetID::TRK) {
268 auto* geom = o2::trk::GeometryTGeo::Instance();
269 geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G));
270 geom->Print();
271 mDigitizer.setGeometry(geom);
273 } else {
274 auto* geom = o2::ft3::GeometryTGeo::Instance();
275 geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G));
276 geom->Print();
277 mDigitizer.setGeometry(geom);
278 mLayers = getNLayers<N>();
279 }
280 if (mLayers > static_cast<int>(o2::trkft3::DigiParams<N>::getMaxLayers())) {
281 LOGP(fatal, "{} geometry has {} layers, but DigiParams supports at most {}", ID.getName(), mLayers, o2::trkft3::DigiParams<N>::getMaxLayers());
282 }
283 mDigits.resize(mLayers);
284 mROFRecords.resize(mLayers);
285 mROFRecordsAccum.resize(mLayers);
286 mLabels.resize(mLayers);
287 mLabelsAccum.resize(mLayers);
288
289 for (int iLayer = 0; iLayer < mLayers; ++iLayer) {
290 const int parLayer = std::min<int>(iLayer, o2::trk::AlmiraParam::getNLayers() - 1);
291 const auto roFrameLengthInBC = aopt.getROFLengthInBC(parLayer);
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(parLayer) + aopt.getROFDelayInBC(parLayer), iLayer);
296 digipar.setStrobeDelay(aopt.getStrobeDelay(parLayer), iLayer);
297 const auto strobeLengthCont = aopt.getStrobeLengthCont(parLayer);
298 digipar.setStrobeLength(strobeLengthCont > 0 ? strobeLengthCont : frameNS - aopt.getStrobeDelay(parLayer), 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) << ID.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*>((std::string(ID.getName()) + "_aptsresp").c_str());
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(Origin, "ALMIRAPARAM", 0)) {
325 LOG(info) << ID.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(Origin, "APTSRESP", 0)) {
336 LOG(info) << ID.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 o2::trkft3::Digitizer<N> mDigitizer{};
356 int mLayers{0};
357 std::vector<std::vector<o2::trkft3::Digit>> mDigits{};
358 std::vector<std::vector<o2::trkft3::ROFRecord>> mROFRecords{};
359 std::vector<std::vector<o2::trkft3::ROFRecord>> mROFRecordsAccum{};
360 std::vector<o2::trkft3::Hit> mHits{};
361 std::vector<o2::trkft3::Hit>* mHitsP{&mHits};
362 std::vector<o2::dataformats::MCTruthContainer<o2::MCCompLabel>> mLabels{};
363 std::vector<o2::dataformats::MCTruthContainer<o2::MCCompLabel>> mLabelsAccum{};
364 std::vector<TChain*> mSimChains{};
366};
367
368DataProcessorSpec getTRKDigitizerSpec(int channel, bool mctruth)
369{
370 std::string detStr = o2::detectors::DetID::getName(o2::detectors::DetID::TRK);
371 auto detOrig = o2::header::gDataOriginTRK;
372 std::vector<InputSpec> inputs;
373 inputs.emplace_back("collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe);
374 // inputs.emplace_back("TRK_almiraparam", "TRK", "ALMIRAPARAM", 0, Lifetime::Condition, ccdbParamSpec("TRK/Config/AlmiraParam"));
375 // if (oTRKParams::Instance().useDeadChannelMap) {
376 // inputs.emplace_back("TRK_dead", "TRK", "DEADMAP", 0, Lifetime::Condition, ccdbParamSpec("TRK/Calib/DeadMap"));
377 // }
378 inputs.emplace_back("TRK_aptsresp", "TRK", "APTSRESP", 0, Lifetime::Condition, ccdbParamSpec("IT3/Calib/APTSResponse"));
379
380 return DataProcessorSpec{detStr + "Digitizer",
381 inputs, makeOutChannels(detOrig, getNLayers<o2::detectors::DetID::TRK>(), mctruth),
382 AlgorithmSpec{adaptFromTask<TRKFT3DPLDigitizerTask<o2::detectors::DetID::TRK>>(mctruth)},
383 Options{
384 {"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}},
385 {"local-response-file", o2::framework::VariantType::String, "", {"use response file saved locally at this path/filename"}}}};
386}
387
388DataProcessorSpec getFT3DigitizerSpec(int channel, bool mctruth)
389{
390 std::string detStr = o2::detectors::DetID::getName(o2::detectors::DetID::FT3);
391 auto detOrig = o2::header::gDataOriginFT3;
392 std::vector<InputSpec> inputs;
393 inputs.emplace_back("collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe);
394 inputs.emplace_back("FT3_aptsresp", "FT3", "APTSRESP", 0, Lifetime::Condition, ccdbParamSpec("IT3/Calib/APTSResponse"));
395
396 return DataProcessorSpec{detStr + "Digitizer",
397 inputs, makeOutChannels(detOrig, getNLayers<o2::detectors::DetID::FT3>(), mctruth),
398 AlgorithmSpec{adaptFromTask<TRKFT3DPLDigitizerTask<o2::detectors::DetID::FT3>>(mctruth)},
399 Options{
400 {"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}},
401 {"local-response-file", o2::framework::VariantType::String, "", {"use response file saved locally at this path/filename"}}}};
402}
403
404} // namespace o2::trkft3
Definition of the base digitizer task class.
A const (ready only) version of MCTruthContainer.
o2::framework::DataAllocator::SubSpecificationType SubSpecificationType
std::ostringstream debug
uint64_t bc
Definition RawEventData.h:5
Header of the General Run Parameters object.
specs of the ALICE3 TRK
Definition of the GeometryTGeo class.
Definition of the TRK/FT3 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:60
static constexpr const char * getName(ID id)
names of defined detectors
Definition DetID.h:148
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.
static GeometryTGeo * Instance()
bool initSimChains(o2::detectors::DetID detid, std::vector< TChain * > &simchains) const
static GeometryTGeo * Instance()
void setResponse(const o2::itsmft::AlpideSimResponse *)
int getROFrameBiasInBC(int layer) const
Definition DigiParams.h:95
int getROFrameLengthInBC(int layer) const
Definition DigiParams.h:78
void setROFRecords(std::vector< o2::trkft3::ROFRecord > *rec)
Definition Digitizer.h:52
void setGeometry(const GeometryTGeo *gm)
Definition Digitizer.h:79
void setEventTime(const o2::InteractionTimeRecord &irt, int layer)
void process(const std::vector< o2::trkft3::Hit > *hits, int evID, int srcID, int layer)
Steer conversion of hits to digits.
void setResponseName(const std::string &name)
Definition Digitizer.h:53
void setMCLabels(o2::dataformats::MCTruthContainer< o2::MCCompLabel > *mclb)
Definition Digitizer.h:51
void fillOutputContainer(uint32_t maxFrame, int layer)
o2::trkft3::DigiParams< DetID > & getParams()
Definition Digitizer.h:55
void setDigits(std::vector< o2::trkft3::Digit > *dig)
Definition Digitizer.h:50
void run(framework::ProcessingContext &pc)
void initDigitizerTask(framework::InitContext &ic) override
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj)
static constexpr o2::header::DataOrigin Origin
static constexpr o2::detectors::DetID ID
void updateTimeDependentParams(ProcessingContext &pc)
GLuint GLuint end
Definition glcorearb.h:469
constexpr o2::header::DataOrigin gDataOriginTRK
Definition DataHeader.h:584
constexpr o2::header::DataOrigin gDataOriginFT3
Definition DataHeader.h:585
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 getTRKDigitizerSpec(int channel, bool mctruth)
DataProcessorSpec getFT3DigitizerSpec(int channel, bool mctruth)
void empty(int)
class listing possible services
int getNOrbitsPerTF() const
get IR corresponding to start of the HBF
Definition HBFUtils.h:49
static constexpr size_t getNLayers()
Definition AlmiraParam.h:30
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)