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: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.
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
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 getTRKDigitizerSpec(int channel, bool mctruth)
DataProcessorSpec getFT3DigitizerSpec(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:30
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)