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
34#include "Framework/Lifetime.h"
35#include "Framework/Output.h"
36#include "Framework/Task.h"
37#include "Framework/Logger.h"
38
48#include "MCHBase/Error.h"
49#include "MCHBase/ErrorMap.h"
51#include "MCHTracking/Track.h"
55
56namespace o2
57{
58namespace mch
59{
60
61using namespace std;
62using namespace o2::framework;
63
64template <typename T>
66{
67 public:
68 //_________________________________________________________________________________________________
69 TrackFinderTask(bool computeTime, bool digits, std::shared_ptr<base::GRPGeomRequest> req)
70 : mComputeTime(computeTime), mDigits(digits), mCCDBRequest(req) {}
71
72 //_________________________________________________________________________________________________
74 {
76
77 LOG(info) << "initializing track finder";
78
79 if (mCCDBRequest) {
81 } else {
82 auto grpFile = ic.options().get<std::string>("grp-file");
83 if (std::filesystem::exists(grpFile)) {
84 const auto grp = parameters::GRPObject::loadFrom(grpFile);
87 } else {
88 float l3Current = ic.options().get<float>("l3Current");
89 float dipoleCurrent = ic.options().get<float>("dipoleCurrent");
90 mTrackFinder.initField(l3Current, dipoleCurrent);
91 }
92 }
93
94 auto config = ic.options().get<std::string>("mch-config");
95 if (!config.empty()) {
96 o2::conf::ConfigurableParam::updateFromFile(config, "MCHTracking", true);
97 }
98 mTrackFinder.init();
99
100 auto debugLevel = ic.options().get<int>("mch-debug");
101 mTrackFinder.debug(debugLevel);
102
103 auto stop = [this]() {
104 mTrackFinder.printStats();
105 mTrackFinder.printTimers();
106 LOG(info) << "tracking duration = " << mElapsedTime.count() << " s";
107 mErrorMap.forEach([](Error error) {
108 LOGP(warning, "{}", error.asString());
109 });
110 };
111 ic.services().get<CallbackService>().set<CallbackService::Id::Stop>(stop);
112 }
113
114 //_________________________________________________________________________________________________
116 {
118 if (mCCDBRequest && base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) {
119 if (matcher == framework::ConcreteDataMatcher("GLO", "GRPMAGFIELD", 0)) {
121 }
122 }
123 }
124
125 //_________________________________________________________________________________________________
127 {
129
130 if (mCCDBRequest) {
132 }
133
134 uint32_t firstTForbit = pc.services().get<o2::framework::TimingInfo>().firstTForbit;
135
136 // get the input messages with clusters and associated digits if needed
137 auto clusterROFs = pc.inputs().get<gsl::span<ROFRecord>>("clusterrofs");
138 auto clustersIn = pc.inputs().get<gsl::span<Cluster>>("clusters");
139 gsl::span<const Digit> digitsIn{};
140 if (mComputeTime || mDigits) {
141 digitsIn = pc.inputs().get<gsl::span<Digit>>("clusterdigits");
142 }
143
144 // create the output messages for tracks, attached clusters and associated digits if requested
145 auto& trackROFs = pc.outputs().make<std::vector<ROFRecord>>(OutputRef{"trackrofs"});
146 auto& mchTracks = pc.outputs().make<std::vector<TrackMCH>>(OutputRef{"tracks"});
147 auto& usedClusters = pc.outputs().make<std::vector<Cluster>>(OutputRef{"trackclusters"});
148 std::vector<Digit, o2::pmr::polymorphic_allocator<Digit>>* usedDigits(nullptr);
149 if (mDigits) {
150 usedDigits = &pc.outputs().make<std::vector<Digit>>(OutputRef{"trackdigits"});
151 }
152
153 trackROFs.reserve(clusterROFs.size());
154 auto timeStart = std::chrono::high_resolution_clock::now();
155 auto& errorMap = mTrackFinder.getErrorMap();
156 errorMap.clear();
157
158 for (const auto& clusterROF : clusterROFs) {
159
160 // run the track finder
161 auto tStart = std::chrono::high_resolution_clock::now();
162 const auto& tracks = mTrackFinder.findTracks(clustersIn.subspan(clusterROF.getFirstIdx(), clusterROF.getNEntries()));
163 auto tEnd = std::chrono::high_resolution_clock::now();
164 mElapsedTime += tEnd - tStart;
165
166 // fill the ouput messages
167 int trackOffset(mchTracks.size());
168 writeTracks(tracks, digitsIn, clusterROF, firstTForbit, mchTracks, usedClusters, usedDigits);
169 trackROFs.emplace_back(clusterROF.getBCData(), trackOffset, mchTracks.size() - trackOffset,
170 clusterROF.getBCWidth());
171 }
172
173 // create the output message for tracking errors
174 auto& trackErrors = pc.outputs().make<std::vector<Error>>(OutputRef{"trackerrors"});
175 errorMap.forEach([&trackErrors](Error error) {
176 trackErrors.emplace_back(error);
177 });
178 mErrorMap.add(errorMap);
179
180 auto timeEnd = std::chrono::high_resolution_clock::now();
181 std::chrono::duration<double, std::milli> elapsed = timeEnd - timeStart;
182 LOGP(info, "Found {:3d} MCH tracks from {:4d} clusters in {:2d} ROFs in {:8.0f} ms",
183 mchTracks.size(), clustersIn.size(), clusterROFs.size(), elapsed.count());
184 }
185
186 private:
187 //_________________________________________________________________________________________________
188 TrackMCH::Time computeTrackTime(const Track& track, const gsl::span<const Digit>& digitsIn,
189 const ROFRecord& clusterROF, uint32_t firstTForbit) const
190 {
192
193 double trackBCinTF = 0.;
194 int nDigits = 0;
195
196 // loop over associated digits and compute the average digits time
197 for (const auto& param : track) {
198 for (const auto& digit : digitsIn.subspan(param.getClusterPtr()->firstDigit, param.getClusterPtr()->nDigits)) {
199 nDigits += 1;
200 trackBCinTF += (double(digit.getTime()) - trackBCinTF) / nDigits;
201 }
202 }
203
204 // set the track time from the computed average digits time
205 if (nDigits > 0) {
206 // convert the average digit time from bunch-crossing units to microseconds
207 // add 1.5 BC to account for the fact that the actual digit time in BC units
208 // can be between t and t+3, hence t+1.5 in average
209 float tMean = o2::constants::lhc::LHCBunchSpacingMUS * (trackBCinTF + 1.5);
210 float tErr = o2::constants::lhc::LHCBunchSpacingMUS * mTrackTime3Sigma;
211 return TrackMCH::Time(tMean, tErr);
212 }
213
214 // if no digits are found, compute the time directly from the cluster's ROF
215 LOG(fatal) << "MCH: no digits found when computing the track mean time";
216 return clusterROF.getTimeMUS({0, firstTForbit}).first;
217 }
218
219 //_________________________________________________________________________________________________
220 void writeTracks(const std::list<Track>& tracks, const gsl::span<const Digit>& digitsIn,
221 const ROFRecord& clusterROF, uint32_t firstTForbit,
222 std::vector<TrackMCH, o2::pmr::polymorphic_allocator<TrackMCH>>& mchTracks,
223 std::vector<Cluster, o2::pmr::polymorphic_allocator<Cluster>>& usedClusters,
224 std::vector<Digit, o2::pmr::polymorphic_allocator<Digit>>* usedDigits) const
225 {
227
228 // map the location of the attached digits between the digitsIn and the usedDigits lists
229 std::unordered_map<uint32_t, uint32_t> digitLocMap{};
230
231 for (const auto& track : tracks) {
232
233 TrackParam paramAtMID(track.last());
234 if (!TrackExtrap::extrapToMID(paramAtMID)) {
235 LOG(warning) << "propagation to MID failed --> track discarded";
236 continue;
237 }
238
239 const auto time = mComputeTime ? computeTrackTime(track, digitsIn, clusterROF, firstTForbit)
240 : clusterROF.getTimeMUS({0, firstTForbit}).first;
241
242 const auto& param = track.first();
243 mchTracks.emplace_back(param.getZ(), param.getParameters(), param.getCovariances(),
244 param.getTrackChi2(), usedClusters.size(), track.getNClusters(),
245 paramAtMID.getZ(), paramAtMID.getParameters(), paramAtMID.getCovariances(),
246 time);
247
248 for (const auto& param : track) {
249
250 usedClusters.emplace_back(*param.getClusterPtr());
251
252 if (mDigits) {
253
254 // map the location of the digits associated to this cluster in the usedDigits list, if not already done
255 auto& cluster = usedClusters.back();
256 auto digitLoc = digitLocMap.emplace(cluster.firstDigit, usedDigits->size());
257
258 // add the digits associated to this cluster if not already there
259 if (digitLoc.second) {
260 auto itFirstDigit = digitsIn.begin() + cluster.firstDigit;
261 usedDigits->insert(usedDigits->end(), itFirstDigit, itFirstDigit + cluster.nDigits);
262 }
263
264 // make the cluster point to the associated digits in the usedDigits list
265 cluster.firstDigit = digitLoc.first->second;
266 }
267 }
268 }
269 }
270
271 bool mComputeTime = false;
272 bool mDigits = false;
273 std::shared_ptr<base::GRPGeomRequest> mCCDBRequest{};
274 float mTrackTime3Sigma{6.0};
275 T mTrackFinder{};
276 ErrorMap mErrorMap{};
277 std::chrono::duration<double> mElapsedTime{};
278};
279
280//_________________________________________________________________________________________________
282 bool disableCCDBMagField, bool original)
283{
284 std::vector<InputSpec> inputSpecs{};
285 inputSpecs.emplace_back(InputSpec{"clusterrofs", "MCH", "CLUSTERROFS", 0, Lifetime::Timeframe});
286 inputSpecs.emplace_back(InputSpec{"clusters", "MCH", "GLOBALCLUSTERS", 0, Lifetime::Timeframe});
287 if (computeTime || digits) {
288 inputSpecs.emplace_back(InputSpec{"clusterdigits", "MCH", "CLUSTERDIGITS", 0, Lifetime::Timeframe});
289 }
290
291 std::vector<OutputSpec> outputSpecs{};
292 outputSpecs.emplace_back(OutputSpec{{"trackrofs"}, "MCH", "TRACKROFS", 0, Lifetime::Timeframe});
293 outputSpecs.emplace_back(OutputSpec{{"tracks"}, "MCH", "TRACKS", 0, Lifetime::Timeframe});
294 outputSpecs.emplace_back(OutputSpec{{"trackclusters"}, "MCH", "TRACKCLUSTERS", 0, Lifetime::Timeframe});
295 if (digits) {
296 outputSpecs.emplace_back(OutputSpec{{"trackdigits"}, "MCH", "TRACKDIGITS", 0, Lifetime::Timeframe});
297 }
298 outputSpecs.emplace_back(OutputSpec{{"trackerrors"}, "MCH", "TRACKERRORS", 0, Lifetime::Timeframe});
299
300 auto ccdbRequest = disableCCDBMagField ? nullptr
301 : std::make_shared<base::GRPGeomRequest>(false, // orbitResetTime
302 false, // GRPECS=true
303 false, // GRPLHCIF
304 true, // GRPMagField
305 false, // askMatLUT
306 base::GRPGeomRequest::None, // geometry
307 inputSpecs);
308
309 return DataProcessorSpec{
310 specName,
311 inputSpecs,
312 outputSpecs,
313 original ? AlgorithmSpec{adaptFromTask<TrackFinderTask<TrackFinderOriginal>>(computeTime, digits, ccdbRequest)}
314 : AlgorithmSpec{adaptFromTask<TrackFinderTask<TrackFinder>>(computeTime, digits, ccdbRequest)},
315 Options{{"l3Current", VariantType::Float, -30000.0f, {"L3 current"}},
316 {"dipoleCurrent", VariantType::Float, -6000.0f, {"Dipole current"}},
317 {"grp-file", VariantType::String, o2::base::NameConf::getGRPFileName(), {"Name of the grp file"}},
318 {"mch-config", VariantType::String, "", {"JSON or INI file with tracking parameters"}},
319 {"mch-debug", VariantType::Int, 0, {"debug level"}}}};
320}
321
322} // namespace mch
323} // 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.
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 int initFieldFromGRP(const o2::parameters::GRPMagField *grp, bool verbose=false)
static void updateFromFile(std::string const &, std::string const &paramsList="", bool unchangedOnly=false)
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
int getNClusters() const
Return the number of attached clusters.
Definition Track.h:44
const TrackParam & first() const
Return a reference to the track parameters at first cluster.
Definition Track.h:50
const TrackParam & last() const
Return a reference to the track parameters at last cluster.
Definition Track.h:52
static GRPObject * loadFrom(const std::string &grpFileName="")
GLenum GLfloat param
Definition glcorearb.h:271
constexpr double LHCBunchSpacingMUS
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
std::vector< ConfigParamSpec > Options
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::@454 tracks
structure to keep trigger-related info
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
Defining DataPointCompositeObject explicitly as copiable.
std::string asString() const
Definition Error.cxx:86
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< Digit > digits