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"
19#include "Headers/DataHeader.h"
20#include "TStopwatch.h"
21#include "TChain.h"
22#include "Steer/HitProcessingManager.h" // for DigitizationContext
25#include "Framework/Task.h"
30#include "DataFormatsTRD/Hit.h"
31#include "DataFormatsTRD/Digit.h" // for the Digit type
34#include "TRDSimulation/Detector.h" // for the Hit type
37#include <chrono>
38
39using namespace o2::framework;
41
42namespace o2
43{
44namespace trd
45{
46
48{
49 public:
50 TRDDPLDigitizerTask() : o2::base::BaseDPLDigitizer(o2::base::InitServices::GEOM | o2::base::InitServices::FIELD) {}
51
53 {
54 LOG(info) << "initializing TRD digitization";
55 mDigitizer.init();
56 }
57
59 {
60 static bool finished = false;
61 if (finished) {
62 return;
63 }
64 LOG(info) << "Doing TRD digitization";
65
66 bool mctruth = pc.outputs().isAllowed({"TRD", "LABELS", 0});
67
68 pc.inputs().get<o2::trd::CalVdriftExB*>("calvdexb");
69 pc.inputs().get<o2::trd::CalGain*>("calgain");
70 pc.inputs().get<std::array<int, constants::MAXCHAMBER>*>("fedchamberstatus");
71 pc.inputs().get<o2::trd::PadStatus*>("padstatus");
72 pc.inputs().get<o2::trd::LocalGainFactor*>("localgainfactor");
73
74 // read collision context from input
75 auto context = pc.inputs().get<o2::steer::DigitizationContext*>("collisioncontext");
76 context->initSimChains(o2::detectors::DetID::TRD, mSimChains);
77 auto& irecords = context->getEventRecords();
78
79 for (auto& record : irecords) {
80 LOG(debug) << "TRD TIME RECEIVED " << record.getTimeNS();
81 }
82
83 auto& eventParts = context->getEventParts();
84 std::vector<o2::trd::Digit> digitsAccum; // accumulator for digits
86 std::vector<TriggerRecord> triggers;
87
88 std::vector<o2::trd::Digit> digits; // digits which get filled
90
91 o2::InteractionTimeRecord currentTime; // the current time
92 o2::InteractionTimeRecord previousTime; // the time of the previous collision
93 o2::InteractionTimeRecord triggerTime; // the time at which the TRD start reading out a signal
94 size_t currTrig = 0; // from which collision is the current TRD trigger (only needed for debug information)
95 bool firstEvent = true; // Flag for the first event processed
96
97 // the interaction record marking the timeframe start
98 auto firstTF = InteractionTimeRecord(o2::raw::HBFUtils::Instance().getFirstSampledTFIR(), 0);
99
100 TStopwatch timer;
101 timer.Start();
102 // loop over all composite collisions given from context
103 // (aka loop over all the interaction records)
104 for (size_t collID = 0; collID < irecords.size(); ++collID) {
105 LOGF(debug, "Collision %lu out of %lu at %.1f ns started processing. Current pileup container size: %lu. Current number of digits accumulated: %lu",
106 collID, irecords.size(), irecords[collID].getTimeNS(), mDigitizer.getPileupSignals().size(), digitsAccum.size());
107 currentTime = irecords[collID];
108
109 // Note: Very crude filter to neglect collisions coming before
110 // the first interaction record of the timeframe. Remove this, once these collisions can be handled
111 // within the digitization routine. Collisions before this timeframe might impact digits of this timeframe.
112 // See https://its.cern.ch/jira/browse/O2-5395.
113 if (currentTime < firstTF) {
114 LOG(info) << "Too early: Not digitizing collision " << collID;
115 continue;
116 }
117
118 // Trigger logic implemented here
119 bool isNewTrigger = true; // flag newly accepted readout trigger
120 if (firstEvent) {
121 triggerTime = currentTime;
122 firstEvent = false;
123 } else {
124 double dT = currentTime.getTimeNS() - triggerTime.getTimeNS();
125 if (dT < mParams.busyTimeNS()) {
126 // busyTimeNS = readoutTimeNS + deadTimeNS, if less than that, pile up the signals and update the last time
127 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);
128 isNewTrigger = false;
129 mDigitizer.pileup();
130 } else {
131 // A new signal can be received, and the detector read it out:
132 // flush previous stored digits, labels and keep a trigger record
133 // then update the trigger time to the new one
134 if (mDigitizer.getPileupSignals().size() > 0) {
135 // in case the pileup container is not empty only signal stored in there is considered
136 mDigitizer.pileup(); // so we have to move the signals from the previous collision into the pileup container here
137 }
138 mDigitizer.flush(digits, labels);
139 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());
140 assert(digits.size() == labels.getIndexedSize());
141 // Add trigger record, and send digits to the accumulator
142 triggers.emplace_back(triggerTime, digitsAccum.size(), digits.size());
143 std::copy(digits.begin(), digits.end(), std::back_inserter(digitsAccum));
144 if (mctruth) {
145 labelsAccum.mergeAtBack(labels);
146 }
147 triggerTime = currentTime;
148 digits.clear();
149 labels.clear();
150 if (triggerTime.getTimeNS() - previousTime.getTimeNS() > mParams.busyTimeNS()) {
151 // we safely clear all pileup signals, because any previous collision cannot contribute signal anymore
152 mDigitizer.clearPileupSignals();
153 }
154 }
155 }
156
157 mDigitizer.setEventTime(currentTime.getTimeNS());
158 if (isNewTrigger) {
159 mDigitizer.setTriggerTime(triggerTime.getTimeNS());
160 currTrig = collID;
161 }
162
163 // for each collision, loop over the constituents event and source IDs
164 // (background signal merging is basically taking place here)
165 for (auto& part : eventParts[collID]) {
166 mDigitizer.setEventID(part.entryID);
167 mDigitizer.setSrcID(part.sourceID);
168 // get the hits for this event and this source and process them
169 std::vector<o2::trd::Hit> hits;
170 context->retrieveHits(mSimChains, "TRDHit", part.sourceID, part.entryID, &hits);
171 LOGF(debug, "Collision %lu processing in total %lu hits", collID, hits.size());
172 mDigitizer.process(hits);
173 }
174 previousTime = currentTime;
175 }
176
177 // Force flush of the digits that remain in the digitizer cache
178 if (mDigitizer.getPileupSignals().size() > 0) {
179 // remember to move signals to pileup container in case it is not empty
180 mDigitizer.pileup();
181 }
182 mDigitizer.flush(digits, labels);
183 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());
184 assert(digits.size() == labels.getIndexedSize());
185 triggers.emplace_back(triggerTime, digitsAccum.size(), digits.size());
186 std::copy(digits.begin(), digits.end(), std::back_inserter(digitsAccum));
187 if (mctruth) {
188 labelsAccum.mergeAtBack(labels);
189 }
190 LOGF(info, "List of TRD chambers with at least one drift velocity out of range: %s", mDigitizer.dumpFlaggedChambers());
191 timer.Stop();
192 LOGF(info, "TRD digitization timing: Cpu: %.3e Real: %.3e s", timer.CpuTime(), timer.RealTime());
193
194 LOG(info) << "TRD: Sending " << digitsAccum.size() << " digits";
195 pc.outputs().snapshot(Output{"TRD", "DIGITS", 1}, digitsAccum);
196 if (mctruth) {
197 LOG(info) << "TRD: Sending " << labelsAccum.getNElements() << " labels";
198 // we are flattening the labels and write to managed shared memory container for further communication
199 auto& sharedlabels = pc.outputs().make<o2::dataformats::ConstMCTruthContainer<o2::MCCompLabel>>(Output{"TRD", "LABELS", 0});
200 labelsAccum.flatten_to(sharedlabels);
201 }
202 LOG(info) << "TRD: Sending ROMode= " << mROMode << " to GRPUpdater";
203 pc.outputs().snapshot(Output{"TRD", "ROMode", 0}, mROMode);
204 LOG(info) << "TRD: Sending trigger records";
205 pc.outputs().snapshot(Output{"TRD", "TRKTRGRD", 1}, triggers);
206 // we should be only called once; tell DPL that this process is ready to exit
207 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
208 finished = true;
209 }
210
211 void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj)
212 {
213 if (matcher == ConcreteDataMatcher("TRD", "CALVDRIFTEXB", 0)) {
214 LOG(info) << "CalVdriftExB object has been updated";
215 mDigitizer.setCalVdriftExB((const o2::trd::CalVdriftExB*)obj);
216 return;
217 }
218 if (matcher == ConcreteDataMatcher("TRD", "CALGAIN", 0)) {
219 LOG(info) << "CalGain object has been updated";
220 mDigitizer.setCalGain((const o2::trd::CalGain*)obj);
221 return;
222 }
223 if (matcher == ConcreteDataMatcher("TRD", "FEDCHAMBERSTATUS", 0)) {
224 LOG(info) << "Fed chamber status has been updated";
225 std::array<int, constants::MAXCHAMBER>* fedStatus = (std::array<int, constants::MAXCHAMBER>*)obj;
226 for (int det = 0; det < constants::MAXCHAMBER; det++) {
227 mDigitizer.setFedChamberStatus(det, (*fedStatus)[det]);
228 }
229 return;
230 }
231 if (matcher == ConcreteDataMatcher("TRD", "PADSTATUS", 0)) {
232 LOG(info) << "PadStatus object has been updated";
233 mDigitizer.setPadStatus((const o2::trd::PadStatus*)obj);
234 return;
235 }
236 if (matcher == ConcreteDataMatcher("TRD", "LOCALGAINFACTOR", 0)) {
237 LOG(info) << "LocalGainFactor object has been updated";
238 mDigitizer.setLocalGainFactor((const o2::trd::LocalGainFactor*)obj);
239 return;
240 }
241 }
242
243 private:
244 Digitizer mDigitizer;
245 std::vector<TChain*> mSimChains;
246 const TRDSimParams& mParams{TRDSimParams::Instance()};
247 // RS: at the moment using hardcoded flag for continuos readout
249}; // namespace trd
250
252{
253 // create the full data processor spec using
254 // a name identifier
255 // input description
256 // algorithmic description (here a lambda getting called once to setup the actual processing function)
257 // options that can be used for this processor (here: input file names where to take the hits)
258 std::vector<OutputSpec> outputs;
259 outputs.emplace_back("TRD", "DIGITS", 1, Lifetime::Timeframe);
260 outputs.emplace_back("TRD", "TRKTRGRD", 1, Lifetime::Timeframe);
261 if (mctruth) {
262 outputs.emplace_back("TRD", "LABELS", 0, Lifetime::Timeframe);
263 }
264 outputs.emplace_back("TRD", "ROMode", 0, Lifetime::Timeframe);
265
266 std::vector<InputSpec> inputs;
267 inputs.emplace_back("collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe);
268 inputs.emplace_back("calvdexb", "TRD", "CALVDRIFTEXB", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/CalVdriftExB"));
269 inputs.emplace_back("calgain", "TRD", "CALGAIN", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/CalGain"));
270 inputs.emplace_back("fedchamberstatus", "TRD", "FEDCHAMBERSTATUS", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/DCSDPsFedChamberStatus"));
271 inputs.emplace_back("padstatus", "TRD", "PADSTATUS", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/PadStatus"));
272 inputs.emplace_back("localgainfactor", "TRD", "LOCALGAINFACTOR", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/LocalGainFactor"));
273
274 return DataProcessorSpec{
275 "TRDDigitizer",
276 // Inputs{InputSpec{"collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast<SubSpecificationType>(channel), Lifetime::Timeframe}},
277 inputs,
278 outputs,
279
280 AlgorithmSpec{adaptFromTask<TRDDPLDigitizerTask>()},
281 Options{}};
282}
283
284} // namespace trd
285} // 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
std::ostringstream debug
Header of the General Run Parameters object.
std::vector< o2::MCCompLabel > labels
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
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.
void process(std::vector< Hit > const &)
void setSrcID(int sourceID)
Definition Digitizer.h:66
void setTriggerTime(double t)
Definition Digitizer.h:64
void setPadStatus(const PadStatus *padStatus)
Definition Digitizer.h:77
void setEventID(int entryID)
Definition Digitizer.h:65
const std::deque< std::array< SignalContainer, constants::MAXCHAMBER > > & getPileupSignals() const
Definition Digitizer.h:62
void setLocalGainFactor(const LocalGainFactor *localGain)
Definition Digitizer.h:76
void flush(DigitContainer &, o2::dataformats::MCTruthContainer< MCLabel > &)
Definition Digitizer.cxx:84
void setFedChamberStatus(int det, int value)
Definition Digitizer.h:68
void setEventTime(double timeNS)
Definition Digitizer.h:63
void clearPileupSignals()
Definition Digitizer.h:61
void setCalVdriftExB(const CalVdriftExB *calVdriftExB)
Definition Digitizer.h:67
void setCalGain(const CalGain *calGain)
Definition Digitizer.h:75
std::string dumpFlaggedChambers() const
void initDigitizerTask(framework::InitContext &ic) override
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj)
void run(framework::ProcessingContext &pc)
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)
header::DataHeader::SubSpecificationType SubSpecificationType
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