Project
Loading...
Searching...
No Matches
TrackFinderSpec.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
16
18
19#include <chrono>
20#include <filesystem>
21#include <list>
22#include <memory>
23#include <stdexcept>
24#include <string>
25#include <unordered_map>
26
27#include <gsl/span>
28#include <TMap.h>
29#include <TObjString.h>
30
37#include "Framework/Lifetime.h"
38#include "Framework/Output.h"
39#include "Framework/Task.h"
40#include "Framework/Logger.h"
41
51#include "MCHBase/Error.h"
52#include "MCHBase/ErrorMap.h"
55#include "MCHTracking/Track.h"
59
60namespace o2
61{
62namespace mch
63{
64
65using namespace std;
66using namespace o2::framework;
67
68template <typename T>
70{
71 public:
72 //_________________________________________________________________________________________________
73 TrackFinderTask(bool computeTime, bool digits, std::shared_ptr<base::GRPGeomRequest> req)
74 : mComputeTime(computeTime), mDigits(digits), mCCDBRequest(req) {}
75
76 //_________________________________________________________________________________________________
78 {
80
81 LOG(info) << "initializing track finder";
82
83 if (mCCDBRequest) {
85 } else {
86 auto grpFile = ic.options().get<std::string>("grp-file");
87 if (std::filesystem::exists(grpFile)) {
88 const auto grp = parameters::GRPObject::loadFrom(grpFile);
91 } else {
92 float l3Current = ic.options().get<float>("l3Current");
93 float dipoleCurrent = ic.options().get<float>("dipoleCurrent");
94 mTrackFinder.initField(l3Current, dipoleCurrent);
95 }
96 }
97
98 auto config = ic.options().get<std::string>("mch-config");
99 if (!config.empty()) {
100 o2::conf::ConfigurableParam::updateFromFile(config, "MCHTracking", true);
101 }
102 mTrackFinder.init();
103
104 auto debugLevel = ic.options().get<int>("mch-debug");
105 mTrackFinder.debug(debugLevel);
106
107 auto stop = [this]() {
108 mTrackFinder.printStats();
109 mTrackFinder.printTimers();
110 LOG(info) << "tracking duration = " << mElapsedTime.count() << " s";
111 mErrorMap.forEach([](Error error) {
112 LOGP(warning, "{}", error.asString());
113 });
114 };
115 ic.services().get<CallbackService>().set<CallbackService::Id::Stop>(stop);
116 }
117
118 //_________________________________________________________________________________________________
120 {
122 if (mCCDBRequest && base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) {
123 if (matcher == framework::ConcreteDataMatcher("GLO", "GRPMAGFIELD", 0)) {
125 }
126 }
127 }
128
129 //_________________________________________________________________________________________________
131 {
133
134 if (mCCDBRequest) {
136 }
137 storeConfigs(pc);
138
139 uint32_t firstTForbit = pc.services().get<o2::framework::TimingInfo>().firstTForbit;
140
141 // get the input messages with clusters and associated digits if needed
142 auto clusterROFs = pc.inputs().get<gsl::span<ROFRecord>>("clusterrofs");
143 auto clustersIn = pc.inputs().get<gsl::span<Cluster>>("clusters");
144 gsl::span<const Digit> digitsIn{};
145 if (mComputeTime || mDigits) {
146 digitsIn = pc.inputs().get<gsl::span<Digit>>("clusterdigits");
147 }
148
149 // create the output messages for tracks, attached clusters and associated digits if requested
150 auto& trackROFs = pc.outputs().make<std::vector<ROFRecord>>(OutputRef{"trackrofs"});
151 auto& mchTracks = pc.outputs().make<std::vector<TrackMCH>>(OutputRef{"tracks"});
152 auto& usedClusters = pc.outputs().make<std::vector<Cluster>>(OutputRef{"trackclusters"});
153 std::vector<Digit, o2::pmr::polymorphic_allocator<Digit>>* usedDigits(nullptr);
154 if (mDigits) {
155 usedDigits = &pc.outputs().make<std::vector<Digit>>(OutputRef{"trackdigits"});
156 }
157
158 trackROFs.reserve(clusterROFs.size());
159 auto timeStart = std::chrono::high_resolution_clock::now();
160 auto& errorMap = mTrackFinder.getErrorMap();
161 errorMap.clear();
162
163 for (const auto& clusterROF : clusterROFs) {
164
165 // run the track finder
166 auto tStart = std::chrono::high_resolution_clock::now();
167 const auto& tracks = mTrackFinder.findTracks(clustersIn.subspan(clusterROF.getFirstIdx(), clusterROF.getNEntries()));
168 auto tEnd = std::chrono::high_resolution_clock::now();
169 mElapsedTime += tEnd - tStart;
170
171 // fill the ouput messages
172 int trackOffset(mchTracks.size());
173 writeTracks(tracks, digitsIn, clusterROF, firstTForbit, mchTracks, usedClusters, usedDigits);
174 trackROFs.emplace_back(clusterROF.getBCData(), trackOffset, mchTracks.size() - trackOffset,
175 clusterROF.getBCWidth());
176 }
177
178 // create the output message for tracking errors
179 auto& trackErrors = pc.outputs().make<std::vector<Error>>(OutputRef{"trackerrors"});
180 errorMap.forEach([&trackErrors](Error error) {
181 trackErrors.emplace_back(error);
182 });
183 mErrorMap.add(errorMap);
184
185 auto timeEnd = std::chrono::high_resolution_clock::now();
186 std::chrono::duration<double, std::milli> elapsed = timeEnd - timeStart;
187 LOGP(info, "Found {:3d} MCH tracks from {:4d} clusters in {:2d} ROFs in {:8.0f} ms",
188 mchTracks.size(), clustersIn.size(), clusterROFs.size(), elapsed.count());
189 }
190
191 private:
192 //_________________________________________________________________________________________________
193 TrackMCH::Time computeTrackTime(const Track& track, const gsl::span<const Digit>& digitsIn,
194 const ROFRecord& clusterROF, uint32_t firstTForbit) const
195 {
197
198 double trackBCinTF = 0.;
199 int nDigits = 0;
200
201 // loop over associated digits and compute the average digits time
202 for (const auto& param : track) {
203 for (const auto& digit : digitsIn.subspan(param.getClusterPtr()->firstDigit, param.getClusterPtr()->nDigits)) {
204 nDigits += 1;
205 trackBCinTF += (double(digit.getTime()) - trackBCinTF) / nDigits;
206 }
207 }
208
209 // set the track time from the computed average digits time
210 if (nDigits > 0) {
211 // convert the average digit time from bunch-crossing units to microseconds
212 // add 1.5 BC to account for the fact that the actual digit time in BC units
213 // can be between t and t+3, hence t+1.5 in average
214 float tMean = o2::constants::lhc::LHCBunchSpacingMUS * (trackBCinTF + 1.5);
215 float tErr = o2::constants::lhc::LHCBunchSpacingMUS * mTrackTime3Sigma;
216 return TrackMCH::Time(tMean, tErr);
217 }
218
219 // if no digits are found, compute the time directly from the cluster's ROF
220 LOG(fatal) << "MCH: no digits found when computing the track mean time";
221 return clusterROF.getTimeMUS({0, firstTForbit}).first;
222 }
223
224 //_________________________________________________________________________________________________
225 void writeTracks(const std::list<Track>& tracks, const gsl::span<const Digit>& digitsIn,
226 const ROFRecord& clusterROF, uint32_t firstTForbit,
227 std::vector<TrackMCH, o2::pmr::polymorphic_allocator<TrackMCH>>& mchTracks,
228 std::vector<Cluster, o2::pmr::polymorphic_allocator<Cluster>>& usedClusters,
229 std::vector<Digit, o2::pmr::polymorphic_allocator<Digit>>* usedDigits) const
230 {
232
233 // map the location of the attached digits between the digitsIn and the usedDigits lists
234 std::unordered_map<uint32_t, uint32_t> digitLocMap{};
235
236 for (const auto& track : tracks) {
237
238 TrackParam paramAtMID(track.last());
239 if (!TrackExtrap::extrapToMID(paramAtMID)) {
240 LOG(warning) << "propagation to MID failed --> track discarded";
241 continue;
242 }
243
244 const auto time = mComputeTime ? computeTrackTime(track, digitsIn, clusterROF, firstTForbit)
245 : clusterROF.getTimeMUS({0, firstTForbit}).first;
246
247 const auto& param = track.first();
248 mchTracks.emplace_back(param.getZ(), param.getParameters(), param.getCovariances(),
249 param.getTrackChi2(), usedClusters.size(), track.getNClusters(),
250 paramAtMID.getZ(), paramAtMID.getParameters(), paramAtMID.getCovariances(),
251 time);
252
253 for (const auto& param : track) {
254
255 usedClusters.emplace_back(*param.getClusterPtr());
256
257 if (mDigits) {
258
259 // map the location of the digits associated to this cluster in the usedDigits list, if not already done
260 auto& cluster = usedClusters.back();
261 auto digitLoc = digitLocMap.emplace(cluster.firstDigit, usedDigits->size());
262
263 // add the digits associated to this cluster if not already there
264 if (digitLoc.second) {
265 auto itFirstDigit = digitsIn.begin() + cluster.firstDigit;
266 usedDigits->insert(usedDigits->end(), itFirstDigit, itFirstDigit + cluster.nDigits);
267 }
268
269 // make the cluster point to the associated digits in the usedDigits list
270 cluster.firstDigit = digitLoc.first->second;
271 }
272 }
273 }
274 }
275
276 //_________________________________________________________________________________________________
277 void storeConfigs(ProcessingContext& pc)
278 {
279 static bool first = true;
280 if (first) {
281 first = false;
283 const auto& conf = TrackerParam::Instance();
285 TMap md;
286 md.SetOwnerKeyValue();
287 md.Add(new TObjString(conf.getName().c_str()), new TObjString(o2::conf::ConfigurableParam::asJSON(conf.getName()).c_str()));
288 pc.outputs().snapshot(Output{"META", "MCHTRACKER", 0}, md);
289 }
290 }
291 }
292
293 bool mComputeTime = false;
294 bool mDigits = false;
295 std::shared_ptr<base::GRPGeomRequest> mCCDBRequest{};
296 float mTrackTime3Sigma{6.0};
297 T mTrackFinder{};
298 ErrorMap mErrorMap{};
299 std::chrono::duration<double> mElapsedTime{};
300};
301
302//_________________________________________________________________________________________________
304 bool disableCCDBMagField, bool original)
305{
306 std::vector<InputSpec> inputSpecs{};
307 inputSpecs.emplace_back(InputSpec{"clusterrofs", "MCH", "CLUSTERROFS", 0, Lifetime::Timeframe});
308 inputSpecs.emplace_back(InputSpec{"clusters", "MCH", "GLOBALCLUSTERS", 0, Lifetime::Timeframe});
309 if (computeTime || digits) {
310 inputSpecs.emplace_back(InputSpec{"clusterdigits", "MCH", "CLUSTERDIGITS", 0, Lifetime::Timeframe});
311 }
312
313 std::vector<OutputSpec> outputSpecs{};
314 outputSpecs.emplace_back(OutputSpec{{"trackrofs"}, "MCH", "TRACKROFS", 0, Lifetime::Timeframe});
315 outputSpecs.emplace_back(OutputSpec{{"tracks"}, "MCH", "TRACKS", 0, Lifetime::Timeframe});
316 outputSpecs.emplace_back(OutputSpec{{"trackclusters"}, "MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe});
317 if (digits) {
318 outputSpecs.emplace_back(OutputSpec{{"trackdigits"}, "MCH", "TRACKDIGITS", 0, Lifetime::Timeframe});
319 }
320 outputSpecs.emplace_back(OutputSpec{{"trackerrors"}, "MCH", "TRACKERRORS", 0, Lifetime::Timeframe});
321 outputSpecs.emplace_back("META", "MCHTRACKER", 0, Lifetime::Sporadic);
322
323 auto ccdbRequest = disableCCDBMagField ? nullptr
324 : std::make_shared<base::GRPGeomRequest>(false, // orbitResetTime
325 false, // GRPECS=true
326 false, // GRPLHCIF
327 true, // GRPMagField
328 false, // askMatLUT
329 base::GRPGeomRequest::None, // geometry
330 inputSpecs);
331
332 return DataProcessorSpec{
333 specName,
334 inputSpecs,
335 outputSpecs,
336 original ? AlgorithmSpec{adaptFromTask<TrackFinderTask<TrackFinderOriginal>>(computeTime, digits, ccdbRequest)}
337 : AlgorithmSpec{adaptFromTask<TrackFinderTask<TrackFinder>>(computeTime, digits, ccdbRequest)},
338 Options{{"l3Current", VariantType::Float, -30000.0f, {"L3 current"}},
339 {"dipoleCurrent", VariantType::Float, -6000.0f, {"Dipole current"}},
340 {"grp-file", VariantType::String, o2::base::NameConf::getGRPFileName(), {"Name of the grp file"}},
341 {"mch-config", VariantType::String, "", {"JSON or INI file with tracking parameters"}},
342 {"mch-debug", VariantType::Int, 0, {"debug level"}}}};
343}
344
345} // namespace mch
346} // namespace o2
Definition of the MCH cluster minimal structure.
Definition of the MCH track for internal use.
definition of the MCH processing errors
int16_t time
Definition RawEventData.h:4
Helper for geometry and GRP related CCDB requests.
Header of the General Run Parameters object.
std::vector< o2::itsmft::ROFRecord > trackROFs
std::vector< o2::its::TrackITS > tracks
Configurable parameters for MCH tracking.
Definition of the MCH ROFrame record.
Definition of the Names Generator class.
Definition of tools for track extrapolation.
Definition of a class to reconstruct tracks with the original algorithm.
Definition of a data processor to read clusters, reconstruct tracks and send them.
Definition of a class to reconstruct tracks.
Definition of the MCH track.
Definition of the MCH track parameters for internal use.
const char * specName
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
static std::string getGRPFileName(const std::string_view prefix=STANDARDSIMPREFIX)
Definition NameConf.cxx:59
static std::string getConfigOutputFileName(const std::string &procName, const std::string &confName="", bool json=true)
Definition NameConf.cxx:138
static int initFieldFromGRP(const o2::parameters::GRPMagField *grp, bool verbose=false)
static std::string asJSON(std::string const &keyOnly="")
static void updateFromFile(std::string const &, std::string const &paramsList="", bool unchangedOnly=false)
static void write(std::string const &filename, std::string const &keyOnly="")
void snapshot(const Output &spec, T const &object)
decltype(auto) make(const Output &spec, Args... args)
ServiceRegistryRef services()
Definition InitContext.h:34
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.
HMPID cluster implementation.
Definition Cluster.h:27
void forEach(ErrorFunction f) const
Definition ErrorMap.cxx:90
void add(ErrorType errorType, uint32_t id0, uint32_t id1, uint64_t n=1)
Definition ErrorMap.cxx:33
std::pair< Time, bool > getTimeMUS(const BCData &startIR, uint32_t nOrbits=128, bool printError=false) const
Definition ROFRecord.cxx:35
static void setField()
static bool extrapToMID(TrackParam &trackParam)
void finaliseCCDB(framework::ConcreteDataMatcher &matcher, void *obj)
void run(framework::ProcessingContext &pc)
void init(framework::InitContext &ic)
TrackFinderTask(bool computeTime, bool digits, std::shared_ptr< base::GRPGeomRequest > req)
o2::dataformats::TimeStampWithError< float, float > Time
Definition TrackMCH.h:38
track for internal use
Definition Track.h:33
static GRPObject * loadFrom(const std::string &grpFileName="")
GLint first
Definition glcorearb.h:399
GLenum GLfloat param
Definition glcorearb.h:271
Defining ITS Vertex explicitly as messageable.
Definition Cartesian.h:288
std::vector< ConfigParamSpec > Options
const bool const int TrackITSInternal< NLayers > & track
o2::framework::DataProcessorSpec getTrackFinderSpec(const char *specName="mch-track-finder", bool computeTime=true, bool digits=false, bool disableCCDBMagField=false, bool original=false)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string name
The name of the associated DataProcessorSpec.
Definition DeviceSpec.h:50
size_t inputTimesliceId
The time pipelining id of this particular device.
Definition DeviceSpec.h:68
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Digit > digits