Project
Loading...
Searching...
No Matches
TRDDigitizerSpec.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
17#include "Framework/Lifetime.h"
18#include "Headers/DataHeader.h"
19#include "TStopwatch.h"
20#include "TChain.h"
21#include "Steer/HitProcessingManager.h" // for DigitizationContext
24#include "Framework/Task.h"
29#include "DataFormatsTRD/Hit.h"
30#include "DataFormatsTRD/Digit.h" // for the Digit type
33#include "TRDSimulation/Detector.h" // for the Hit type
36#include <chrono>
37
38using namespace o2::framework;
40
41namespace o2
42{
43namespace trd
44{
45
47{
48 public:
49 TRDDPLDigitizerTask() : o2::base::BaseDPLDigitizer(o2::base::InitServices::GEOM | o2::base::InitServices::FIELD) {}
50
52 {
53 LOG(info) << "initializing TRD digitization";
54 mDigitizer.init();
55 }
56
58 {
59 static bool finished = false;
60 if (finished) {
61 return;
62 }
63 LOG(info) << "Doing TRD digitization";
64
65 bool mctruth = pc.outputs().isAllowed({"TRD", "LABELS", 0});
66
67 Calibrations simcal;
68 // the timestamp can be extracted from the DPL header (it is set in SimReader)
69 auto creationTime = pc.services().get<o2::framework::TimingInfo>().creation;
70 simcal.getCCDBObjects(creationTime);
71 mDigitizer.setCalibrations(&simcal);
72
73 // read collision context from input
74 auto context = pc.inputs().get<o2::steer::DigitizationContext*>("collisioncontext");
75 context->initSimChains(o2::detectors::DetID::TRD, mSimChains);
76 auto& irecords = context->getEventRecords();
77
78 for (auto& record : irecords) {
79 LOG(debug) << "TRD TIME RECEIVED " << record.getTimeNS();
80 }
81
82 auto& eventParts = context->getEventParts();
83 std::vector<o2::trd::Digit> digitsAccum; // accumulator for digits
85 std::vector<TriggerRecord> triggers;
86
87 std::vector<o2::trd::Digit> digits; // digits which get filled
88 o2::dataformats::MCTruthContainer<o2::MCCompLabel> labels; // labels which get filled
89
90 o2::InteractionTimeRecord currentTime; // the current time
91 o2::InteractionTimeRecord previousTime; // the time of the previous collision
92 o2::InteractionTimeRecord triggerTime; // the time at which the TRD start reading out a signal
93 size_t currTrig = 0; // from which collision is the current TRD trigger (only needed for debug information)
94 bool firstEvent = true; // Flag for the first event processed
95
96 // the interaction record marking the timeframe start
97 auto firstTF = InteractionTimeRecord(o2::raw::HBFUtils::Instance().getFirstSampledTFIR(), 0);
98
99 TStopwatch timer;
100 timer.Start();
101 // loop over all composite collisions given from context
102 // (aka loop over all the interaction records)
103 for (size_t collID = 0; collID < irecords.size(); ++collID) {
104 LOGF(debug, "Collision %lu out of %lu at %.1f ns started processing. Current pileup container size: %lu. Current number of digits accumulated: %lu",
105 collID, irecords.size(), irecords[collID].getTimeNS(), mDigitizer.getPileupSignals().size(), digitsAccum.size());
106 currentTime = irecords[collID];
107
108 // Note: Very crude filter to neglect collisions coming before
109 // the first interaction record of the timeframe. Remove this, once these collisions can be handled
110 // within the digitization routine. Collisions before this timeframe might impact digits of this timeframe.
111 // See https://its.cern.ch/jira/browse/O2-5395.
112 if (currentTime < firstTF) {
113 LOG(info) << "Too early: Not digitizing collision " << collID;
114 continue;
115 }
116
117 // Trigger logic implemented here
118 bool isNewTrigger = true; // flag newly accepted readout trigger
119 if (firstEvent) {
120 triggerTime = currentTime;
121 firstEvent = false;
122 } else {
123 double dT = currentTime.getTimeNS() - triggerTime.getTimeNS();
124 if (dT < mParams.busyTimeNS()) {
125 // busyTimeNS = readoutTimeNS + deadTimeNS, if less than that, pile up the signals and update the last time
126 LOGF(debug, "Collision %lu Not creating new trigger at time %.2f since dT=%.2f ns < busy time of %.1f us", collID, currentTime.getTimeNS(), dT, mParams.busyTimeNS() / 1000);
127 isNewTrigger = false;
128 mDigitizer.pileup();
129 } else {
130 // A new signal can be received, and the detector read it out:
131 // flush previous stored digits, labels and keep a trigger record
132 // then update the trigger time to the new one
133 if (mDigitizer.getPileupSignals().size() > 0) {
134 // in case the pileup container is not empty only signal stored in there is considered
135 mDigitizer.pileup(); // so we have to move the signals from the previous collision into the pileup container here
136 }
137 mDigitizer.flush(digits, labels);
138 LOGF(debug, "Collision %lu we got %lu digits and %lu labels. There are %lu pileup containers remaining", currTrig, digits.size(), labels.getNElements(), mDigitizer.getPileupSignals().size());
139 assert(digits.size() == labels.getIndexedSize());
140 // Add trigger record, and send digits to the accumulator
141 triggers.emplace_back(triggerTime, digitsAccum.size(), digits.size());
142 std::copy(digits.begin(), digits.end(), std::back_inserter(digitsAccum));
143 if (mctruth) {
144 labelsAccum.mergeAtBack(labels);
145 }
146 triggerTime = currentTime;
147 digits.clear();
148 labels.clear();
149 if (triggerTime.getTimeNS() - previousTime.getTimeNS() > mParams.busyTimeNS()) {
150 // we safely clear all pileup signals, because any previous collision cannot contribute signal anymore
151 mDigitizer.clearPileupSignals();
152 }
153 }
154 }
155
156 mDigitizer.setEventTime(currentTime.getTimeNS());
157 if (isNewTrigger) {
158 mDigitizer.setTriggerTime(triggerTime.getTimeNS());
159 currTrig = collID;
160 }
161
162 // for each collision, loop over the constituents event and source IDs
163 // (background signal merging is basically taking place here)
164 for (auto& part : eventParts[collID]) {
165 mDigitizer.setEventID(part.entryID);
166 mDigitizer.setSrcID(part.sourceID);
167 // get the hits for this event and this source and process them
168 std::vector<o2::trd::Hit> hits;
169 context->retrieveHits(mSimChains, "TRDHit", part.sourceID, part.entryID, &hits);
170 LOGF(debug, "Collision %lu processing in total %lu hits", collID, hits.size());
171 mDigitizer.process(hits);
172 }
173 previousTime = currentTime;
174 }
175
176 // Force flush of the digits that remain in the digitizer cache
177 if (mDigitizer.getPileupSignals().size() > 0) {
178 // remember to move signals to pileup container in case it is not empty
179 mDigitizer.pileup();
180 }
181 mDigitizer.flush(digits, labels);
182 LOGF(debug, "Collision %lu we got %lu digits and %lu labels. There are %lu pileup containers remaining", currTrig, digits.size(), labels.getNElements(), mDigitizer.getPileupSignals().size());
183 assert(digits.size() == labels.getIndexedSize());
184 triggers.emplace_back(triggerTime, digitsAccum.size(), digits.size());
185 std::copy(digits.begin(), digits.end(), std::back_inserter(digitsAccum));
186 if (mctruth) {
187 labelsAccum.mergeAtBack(labels);
188 }
189 LOGF(info, "List of TRD chambers with at least one drift velocity out of range: %s", mDigitizer.dumpFlaggedChambers());
190 timer.Stop();
191 LOGF(info, "TRD digitization timing: Cpu: %.3e Real: %.3e s", timer.CpuTime(), timer.RealTime());
192
193 LOG(info) << "TRD: Sending " << digitsAccum.size() << " digits";
194 pc.outputs().snapshot(Output{"TRD", "DIGITS", 1}, digitsAccum);
195 if (mctruth) {
196 LOG(info) << "TRD: Sending " << labelsAccum.getNElements() << " labels";
197 // we are flattening the labels and write to managed shared memory container for further communication
198 auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{"TRD", "LABELS", 0});
199 labelsAccum.flatten_to(sharedlabels);
200 }
201 LOG(info) << "TRD: Sending ROMode= " << mROMode << " to GRPUpdater";
202 pc.outputs().snapshot(Output{"TRD", "ROMode", 0}, mROMode);
203 LOG(info) << "TRD: Sending trigger records";
204 pc.outputs().snapshot(Output{"TRD", "TRKTRGRD", 1}, triggers);
205 // we should be only called once; tell DPL that this process is ready to exit
206 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
207 finished = true;
208 }
209
210 private:
211 Digitizer mDigitizer;
212 std::vector<TChain*> mSimChains;
213 const TRDSimParams& mParams{TRDSimParams::Instance()};
214 // RS: at the moment using hardcoded flag for continuos readout
216}; // namespace trd
217
219{
220 // create the full data processor spec using
221 // a name identifier
222 // input description
223 // algorithmic description (here a lambda getting called once to setup the actual processing function)
224 // options that can be used for this processor (here: input file names where to take the hits)
225 std::vector<OutputSpec> outputs;
226 outputs.emplace_back("TRD", "DIGITS", 1, Lifetime::Timeframe);
227 outputs.emplace_back("TRD", "TRKTRGRD", 1, Lifetime::Timeframe);
228 if (mctruth) {
229 outputs.emplace_back("TRD", "LABELS", 0, Lifetime::Timeframe);
230 }
231 outputs.emplace_back("TRD", "ROMode", 0, Lifetime::Timeframe);
232
233 return DataProcessorSpec{
234 "TRDDigitizer",
235 Inputs{InputSpec{"collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe}},
236
237 outputs,
238
239 AlgorithmSpec{adaptFromTask<TRDDPLDigitizerTask>()},
240 Options{}};
241}
242
243} // namespace trd
244} // end namespace o2
Definition of the base digitizer task class.
A const (ready only) version of MCTruthContainer.
Global TRD definitions and constants.
o2::framework::DataAllocator::SubSpecificationType SubSpecificationType
Header of the General Run Parameters object.
std::ostringstream debug
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 constexpr ID TRD
Definition DetID.h:65
void snapshot(const Output &spec, T const &object)
o2::header::DataHeader::SubSpecificationType SubSpecificationType
decltype(auto) make(const Output &spec, Args... args)
bool isAllowed(Output const &query)
check if a certain output is allowed
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
void getCCDBObjects(long timestamp)
void process(std::vector< Hit > const &)
void setSrcID(int sourceID)
Definition Digitizer.h:63
void setTriggerTime(double t)
Definition Digitizer.h:61
void setEventID(int entryID)
Definition Digitizer.h:62
const std::deque< std::array< SignalContainer, constants::MAXCHAMBER > > & getPileupSignals() const
Definition Digitizer.h:59
void flush(DigitContainer &, o2::dataformats::MCTruthContainer< MCLabel > &)
Definition Digitizer.cxx:84
void setEventTime(double timeNS)
Definition Digitizer.h:60
void clearPileupSignals()
Definition Digitizer.h:58
void setCalibrations(Calibrations *calibrations)
Definition Digitizer.h:64
std::string dumpFlaggedChambers() const
void initDigitizerTask(framework::InitContext &ic) override
void run(framework::ProcessingContext &pc)
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::vector< ConfigParamSpec > Options
header::DataHeader::SubSpecificationType SubSpecificationType
std::vector< InputSpec > Inputs
o2::framework::DataProcessorSpec getTRDDigitizerSpec(int channel, bool mctruth=true)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
double getTimeNS() const
get time in ns from orbit=0/bc=0
float busyTimeNS() const
the time for which no new trigger can be received in nanoseconds
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Digit > digits