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
34#include <TChain.h>
35#include <TStopwatch.h>
36
37#include <memory>
38#include <string>
39
40using namespace o2::framework;
42
43namespace
44{
45std::vector<OutputSpec> makeOutChannels(o2::header::DataOrigin detOrig, bool mctruth)
46{
47 std::vector<OutputSpec> outputs;
48 outputs.emplace_back(detOrig, "DIGITS", 0, Lifetime::Timeframe);
49 outputs.emplace_back(detOrig, "DIGITSROF", 0, Lifetime::Timeframe);
50 if (mctruth) {
51 outputs.emplace_back(detOrig, "DIGITSMC2ROF", 0, Lifetime::Timeframe);
52 outputs.emplace_back(detOrig, "DIGITSMCTR", 0, Lifetime::Timeframe);
53 }
54 outputs.emplace_back(detOrig, "ROMode", 0, Lifetime::Timeframe);
55 return outputs;
56}
57} // namespace
58
59namespace o2::trk
60{
61using namespace o2::base;
63{
64 public:
66
67 TRKDPLDigitizerTask(bool mctruth = true) : BaseDPLDigitizer(InitServices::FIELD | InitServices::GEOM), mWithMCTruth(mctruth) {}
68
70 {
71 mDisableQED = ic.options().get<bool>("disable-qed");
72 mLocalRespFile = ic.options().get<std::string>("local-response-file");
73 }
74
76 {
77 if (mFinished) {
78 return;
79 }
81
82 // read collision context from input
83 auto context = pc.inputs().get<o2::steer::DigitizationContext*>("collisioncontext");
84 context->initSimChains(mID, mSimChains);
85 const bool withQED = context->isQEDProvided() && !mDisableQED;
86 auto& timesview = context->getEventRecords(withQED);
87 LOG(info) << "GOT " << timesview.size() << " COLLISION TIMES";
88 LOG(info) << "SIMCHAINS " << mSimChains.size();
89
90 // if there is nothing to do ... return
91 if (timesview.empty()) {
92 return;
93 }
94 TStopwatch timer;
95 timer.Start();
96 LOG(info) << " CALLING TRK DIGITIZATION ";
97
98 mDigitizer.setDigits(&mDigits);
99 mDigitizer.setROFRecords(&mROFRecords);
100 mDigitizer.setMCLabels(&mLabels);
101
102 // digits are directly put into DPL owned resource
103 auto& digitsAccum = pc.outputs().make<std::vector<itsmft::Digit>>(Output{mOrigin, "DIGITS", 0});
104
105 auto accumulate = [this, &digitsAccum]() {
106 // accumulate result of single event processing, called after processing every event supplied
107 // AND after the final flushing via digitizer::fillOutputContainer
108 if (mDigits.empty()) {
109 LOG(debug) << "No digits to accumulate";
110 return; // no digits were flushed, nothing to accumulate
111 }
112 LOG(debug) << "Accumulating " << mDigits.size() << " digits ";
113 auto ndigAcc = digitsAccum.size();
114 std::copy(mDigits.begin(), mDigits.end(), std::back_inserter(digitsAccum));
115
116 // fix ROFrecords references on ROF entries
117 auto nROFRecsOld = mROFRecordsAccum.size();
118
119 for (int i = 0; i < mROFRecords.size(); i++) {
120 auto& rof = mROFRecords[i];
121 rof.setFirstEntry(ndigAcc + rof.getFirstEntry());
122 rof.print();
123
124 if (mFixMC2ROF < mMC2ROFRecordsAccum.size()) { // fix ROFRecord entry in MC2ROF records
125 for (int m2rid = mFixMC2ROF; m2rid < mMC2ROFRecordsAccum.size(); m2rid++) {
126 // need to register the ROFRecors entry for MC event starting from this entry
127 auto& mc2rof = mMC2ROFRecordsAccum[m2rid];
128 if (rof.getROFrame() == mc2rof.minROF) {
129 mFixMC2ROF++;
130 mc2rof.rofRecordID = nROFRecsOld + i;
131 mc2rof.print();
132 }
133 }
134 }
135 }
136
137 std::copy(mROFRecords.begin(), mROFRecords.end(), std::back_inserter(mROFRecordsAccum));
138 if (mWithMCTruth) {
139 mLabelsAccum.mergeAtBack(mLabels);
140 }
141 LOG(info) << "Added " << mDigits.size() << " digits ";
142 // clean containers from already accumulated stuff
143 mLabels.clear();
144 mDigits.clear();
145 mROFRecords.clear();
146 }; // end accumulate lambda
147
148 auto& eventParts = context->getEventParts(withQED);
149 // loop over all composite collisions given from context (aka loop over all the interaction records)
150 const int bcShift = mDigitizer.getParams().getROFrameBiasInBC();
151 // loop over all composite collisions given from context (aka loop over all the interaction records)
152 for (size_t collID = 0; collID < timesview.size(); ++collID) {
153 auto irt = timesview[collID];
154 if (irt.toLong() < bcShift) { // due to the ROF misalignment the collision would go to negative ROF ID, discard
155 continue;
156 }
157 irt -= bcShift; // account for the ROF start shift
158
159 mDigitizer.setEventTime(irt);
160 mDigitizer.resetEventROFrames(); // to estimate min/max ROF for this collID
161 // for each collision, loop over the constituents event and source IDs
162 // (background signal merging is basically taking place here)
163 for (auto& part : eventParts[collID]) {
164
165 // get the hits for this event and this source
166 mHits.clear();
167 context->retrieveHits(mSimChains, o2::detectors::SimTraits::DETECTORBRANCHNAMES[mID][0].c_str(), part.sourceID, part.entryID, &mHits);
168
169 if (!mHits.empty()) {
170 LOG(debug) << "For collision " << collID << " eventID " << part.entryID
171 << " found " << mHits.size() << " hits ";
172 mDigitizer.process(&mHits, part.entryID, part.sourceID); // call actual digitization procedure
173 }
174 }
175 mMC2ROFRecordsAccum.emplace_back(collID, -1, mDigitizer.getEventROFrameMin(), mDigitizer.getEventROFrameMax());
176 accumulate();
177 }
178 mDigitizer.fillOutputContainer();
179 LOG(debug) << "mDigits size after fill: " << mDigits.size();
180 accumulate();
181
182 // here we have all digits and labels and we can send them to consumer (aka snapshot it onto output)
183
184 pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", 0}, mROFRecordsAccum);
185 if (mWithMCTruth) {
186 pc.outputs().snapshot(Output{mOrigin, "DIGITSMC2ROF", 0}, mMC2ROFRecordsAccum);
187 auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{mOrigin, "DIGITSMCTR", 0});
188 mLabelsAccum.flatten_to(sharedlabels);
189 // free space of existing label containers
190 mLabels.clear_andfreememory();
191 mLabelsAccum.clear_andfreememory();
192 }
193 LOG(info) << mID.getName() << ": Sending ROMode= " << mROMode << " to GRPUpdater";
194 pc.outputs().snapshot(Output{mOrigin, "ROMode", 0}, mROMode);
195
196 timer.Stop();
197 LOG(info) << "Digitization took " << timer.CpuTime() << "s";
198
199 // we should be only called once; tell DPL that this process is ready to exit
200 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
201
202 mFinished = true;
203 }
204
206 {
207 std::unique_ptr<TFile> file(TFile::Open(mLocalRespFile.data(), "READ"));
208 if (!file) {
209 LOG(fatal) << "Cannot open response file " << mLocalRespFile;
210 }
211 mDigitizer.getParams().setAlpSimResponse((const o2::itsmft::AlpideSimResponse*)file->Get("response1"));
212 }
213
215 {
216 static bool initOnce{false};
217 if (!initOnce) {
218 initOnce = true;
219 auto& digipar = mDigitizer.getParams();
220
221 // configure digitizer
223 geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)); // make sure L2G matrices are loaded
224 geom->Print();
225 mDigitizer.setGeometry(geom);
226
230 digipar.setContinuous(dopt.continuous);
231 digipar.setROFrameBiasInBC(aopt.roFrameBiasInBC);
232 if (dopt.continuous) {
234 digipar.setROFrameLengthInBC(aopt.roFrameLengthInBC);
235 digipar.setROFrameLength(frameNS); // RO frame in ns
236 digipar.setStrobeDelay(aopt.strobeDelay); // Strobe delay wrt beginning of the RO frame, in ns
237 digipar.setStrobeLength(aopt.strobeLengthCont > 0 ? aopt.strobeLengthCont : frameNS - aopt.strobeDelay); // Strobe length in ns
238 } else {
239 digipar.setROFrameLength(aopt.roFrameLengthTrig); // RO frame in ns
240 digipar.setStrobeDelay(aopt.strobeDelay); // Strobe delay wrt beginning of the RO frame, in ns
241 digipar.setStrobeLength(aopt.strobeLengthTrig); // Strobe length in ns
242 }
243 // parameters of signal time response: flat-top duration, max rise time and q @ which rise time is 0
244 digipar.getSignalShape().setParameters(dopt.strobeFlatTop, dopt.strobeMaxRiseTime, dopt.strobeQRiseTime0);
245 digipar.setChargeThreshold(dopt.chargeThreshold); // charge threshold in electrons
246 digipar.setNoisePerPixel(dopt.noisePerPixel); // noise level
247 digipar.setTimeOffset(dopt.timeOffset);
248 digipar.setNSimSteps(dopt.nSimSteps);
249
251 LOG(info) << mID.getName() << " simulated in "
252 << ((mROMode == o2::parameters::GRPObject::CONTINUOUS) ? "CONTINUOUS" : "TRIGGERED")
253 << " RO mode";
254
255 // if (oTRKParams::Instance().useDeadChannelMap) {
256 // pc.inputs().get<o2::itsmft::NoiseMap*>("TRK_dead"); // trigger final ccdb update
257 // }
258 pc.inputs().get<o2::itsmft::AlpideSimResponse*>("TRK_aptsresp");
259
260 // init digitizer
261 mDigitizer.init();
262 }
263 // Other time-dependent parameters can be added below
264 }
265
266 void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj)
267 {
268 if (matcher == ConcreteDataMatcher(detectors::DetID::ITS, "ALPIDEPARAM", 0)) {
269 LOG(info) << mID.getName() << " Alpide param updated";
271 par.printKeyValues();
272 return;
273 }
274 // if (matcher == ConcreteDataMatcher(mOrigin, "DEADMAP", 0)) {
275 // LOG(info) << mID.getName() << " static dead map updated";
276 // mDigitizer.setDeadChannelsMap((o2::itsmft::NoiseMap*)obj);
277 // return;
278 // }
279 if (matcher == ConcreteDataMatcher(mOrigin, "APTSRESP", 0)) {
280 LOG(info) << mID.getName() << " loaded APTSResponseData";
281 if (mLocalRespFile.empty()) {
282 LOG(info) << "Using CCDB/APTS response file";
284 mDigitizer.setResponseName("APTS");
285 } else {
286 LOG(info) << "Response function will be loaded from local file: " << mLocalRespFile;
288 mDigitizer.setResponseName("ALICE3");
289 }
290 }
291 }
292
293 private:
294 bool mWithMCTruth{true};
295 bool mFinished{false};
296 bool mDisableQED{false};
297 std::string mLocalRespFile{""};
298 const o2::detectors::DetID mID{o2::detectors::DetID::TRK};
300 o2::trk::Digitizer mDigitizer{};
301 std::vector<o2::itsmft::Digit> mDigits{};
302 std::vector<o2::itsmft::ROFRecord> mROFRecords{};
303 std::vector<o2::itsmft::ROFRecord> mROFRecordsAccum{};
304 std::vector<o2::trk::Hit> mHits{};
305 std::vector<o2::trk::Hit>* mHitsP{&mHits};
308 std::vector<o2::itsmft::MC2ROFRecord> mMC2ROFRecordsAccum{};
309 std::vector<TChain*> mSimChains{};
310
311 int mFixMC2ROF = 0; // 1st entry in mc2rofRecordsAccum to be fixed for ROFRecordID
313};
314
315DataProcessorSpec getTRKDigitizerSpec(int channel, bool mctruth)
316{
317 std::string detStr = o2::detectors::DetID::getName(o2::detectors::DetID::TRK);
318 auto detOrig = o2::header::gDataOriginTRK;
319 std::vector<InputSpec> inputs;
320 inputs.emplace_back("collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe);
321 inputs.emplace_back("ITS_alppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam"));
322 // if (oTRKParams::Instance().useDeadChannelMap) {
323 // inputs.emplace_back("TRK_dead", "TRK", "DEADMAP", 0, Lifetime::Condition, ccdbParamSpec("TRK/Calib/DeadMap"));
324 // }
325 inputs.emplace_back("TRK_aptsresp", "TRK", "APTSRESP", 0, Lifetime::Condition, ccdbParamSpec("IT3/Calib/APTSResponse"));
326
327 return DataProcessorSpec{detStr + "Digitizer",
328 inputs, makeOutChannels(detOrig, mctruth),
329 AlgorithmSpec{adaptFromTask<TRKDPLDigitizerTask>(mctruth)},
330 Options{
331 {"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}},
332 {"local-response-file", o2::framework::VariantType::String, "", {"use response file saved locally at this path/filename"}}}};
333}
334
335} // 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
int32_t i
Header of the General Run Parameters object.
Definition of the ITSMFT ROFrame (trigger) record.
Definition of the TRK digitizer.
virtual void init(o2::framework::InitContext &) final
A read-only version of MCTruthContainer allowing for storage optimisation.
A container to hold and manage MC truth information/labels.
void mergeAtBack(MCTruthContainer< TruthElement > const &other)
size_t flatten_to(ContainerType &container) const
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.
bool initSimChains(o2::detectors::DetID detid, std::vector< TChain * > &simchains) const
int getROFrameBiasInBC() const
Definition DigiParams.h:73
void setAlpSimResponse(const o2::itsmft::AlpideSimResponse *)
void setEventTime(const o2::InteractionTimeRecord &irt)
void fillOutputContainer(uint32_t maxFrame=0xffffffff)
o2::trk::DigiParams & getParams()
Definition Digitizer.h:50
void setResponseName(const std::string &name)
Definition Digitizer.h:48
void process(const std::vector< o2::trk::Hit > *hits, int evID, int srcID)
Steer conversion of hits to digits.
uint32_t getEventROFrameMin() const
Definition Digitizer.h:75
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 setGeometry(const o2::trk::GeometryTGeo *gm)
Definition Digitizer.h:73
uint32_t getEventROFrameMax() const
Definition Digitizer.h:76
void resetEventROFrames()
Definition Digitizer.h:77
void Print(Option_t *opt="") const
void fillMatrixCache(int mask)
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
constexpr o2::header::DataOrigin gDataOriginTRK
Definition DataHeader.h:584
constexpr double LHCBunchSpacingNS
Defining PrimaryVertex explicitly as messageable.
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)
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 roFrameLengthInBC
ROF length in BC for continuous mode.
float strobeLengthCont
if < 0, full ROF length - delay
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
static constexpr int L2G
Definition Cartesian.h:54
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"