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.
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:58
static std::string getConfigOutputFileName(const std::string &procName, const std::string &confName="", bool json=true)
Definition NameConf.cxx:120
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="")
GLenum GLfloat param
Definition glcorearb.h:271
constexpr double LHCBunchSpacingMUS
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)
struct o2::upgrades_utils::@469 tracks
structure to keep trigger-related info
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