Project
Loading...
Searching...
No Matches
CheckResidSpec.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
15#include <algorithm>
16#include <array>
17#include <charconv>
18#include <cctype>
19#include <limits>
20#include <optional>
21#include <string_view>
22#include <utility>
23#include <vector>
25#include <TStopwatch.h>
45#include "ITStracking/IOUtils.h"
53#include <TROOT.h>
54#include <TStyle.h>
55#include <TLatex.h>
56#include <TCanvas.h>
57#include <TLegend.h>
58#include <TLegendEntry.h>
59#include <TH1F.h>
60#include <TH2F.h>
61#include <TProfile.h>
62#include <TGraph.h>
63#include <TF1.h>
64#ifdef WITH_OPENMP
65#include <omp.h>
66#endif
67
68// Attention: in case the residuals are checked with geometry different from the one used for initial reconstruction,
69// pass a --configKeyValues option for vertex refit as:
70// ;pvertexer.useMeanVertexConstraint=false;pvertexer.meanVertexExtraErrSelection=0.2;pvertexer.iniScale2=100;pvertexer.acceptableScale2=10.;
71// In any case, it is better to pass ;pvertexer.useMeanVertexConstraint=false;
72
73namespace o2::checkresid
74{
75using namespace o2::framework;
78
85
86class CheckResidSpec final : public Task
87{
88 public:
89 CheckResidSpec(std::shared_ptr<DataRequest> dr, std::shared_ptr<o2::base::GRPGeomRequest> gr, GTrackID::mask_t src, bool drawOnly, bool postProcOnly)
90 : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mDrawOnly(drawOnly), mPostProcOnly(postProcOnly)
91 {
92 }
93 ~CheckResidSpec() final = default;
94 void init(InitContext& ic) final;
95 void run(ProcessingContext& pc) final;
96 void endOfStream(EndOfStreamContext& ec) final;
97 void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final;
98 void process();
99
100 private:
101 void updateTimeDependentParams(ProcessingContext& pc);
102 bool refitPV(o2::dataformats::PrimaryVertex& pv, int vid);
103 bool refitITStrack(o2::track::TrackParCov& track, GTrackID gid);
104 bool processITSTrack(const o2::its::TrackITS& iTrack, const o2::dataformats::PrimaryVertex& pv, o2::checkresid::Track& resTrack, o2::track::PID pid);
105 void bookHistos();
106 void fillHistos(const o2::checkresid::Track& trc);
107 void postProcessHistos();
108 void drawHistos();
109
110 o2::itsmft::ChipMappingITS mChipMap;
111 o2::globaltracking::RecoContainer* mRecoData = nullptr;
112 int mNThreads = 1;
113 bool mMeanVertexUpdated = false;
114 float mITSROFrameLengthMUS = 0.f;
115 o2::dataformats::MeanVertexObject mMeanVtx{};
116 ITSClusters mITSClustersArray;
117 std::vector<int16_t> mITSClusterSizes;
118 const o2::itsmft::TopologyDictionary* mITSDict = nullptr;
119 o2::vertexing::PVertexer mVertexer;
120 std::shared_ptr<DataRequest> mDataRequest;
121 std::shared_ptr<o2::base::GRPGeomRequest> mGGCCDBRequest;
122 std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOut;
123 GTrackID::mask_t mTracksSrc{};
124
125 bool mDrawOnly = false;
126 bool mPostProcOnly = false;
127 bool mDraw = false;
128 bool mFillHistos = true;
129 bool mFillTree = true;
130 std::vector<std::unique_ptr<o2::HistoManager>> mHManV{};
131 std::vector<o2::dataformats::PrimaryVertex> mPVUsed;
132 o2::HistoManager* mHMan = nullptr;
133};
134
136{
137 mDraw = true;
138 if (!mDrawOnly) {
139 mDraw = ic.options().get<bool>("draw-report");
140 mFillHistos = !ic.options().get<bool>("no-hist");
141 mFillTree = !ic.options().get<bool>("no-tree");
142 mNThreads = ic.options().get<int>("nthreads");
143 }
145 int lane = ic.services().get<const o2::framework::DeviceSpec>().inputTimesliceId;
146 int maxLanes = ic.services().get<const o2::framework::DeviceSpec>().maxInputTimeslices;
147 std::string nm = params.outname;
148 if (maxLanes > 1) {
149 o2::conf::ConfigurableParam::updateFromString(fmt::format("checkresid.outname={}_t{}", nm, lane));
150 }
151 if (mDraw) {
152 mFillHistos = true;
153 }
154 if (!mDrawOnly && mFillHistos) {
155 bookHistos();
156 }
157 if (!params.ext_hm_list.empty()) {
158 auto vecNames = o2::utils::Str::tokenize(params.ext_hm_list, ",;");
159 auto vecLegends = o2::utils::Str::tokenize(params.ext_leg_list, ',');
160 bool useLeg = true;
161 if (vecNames.size() != vecLegends.size()) {
162 LOGP(warn, "{} legend names provided for {} external histomanagers, will use file names as legends", vecLegends.size(), vecNames.size());
163 useLeg = false;
164 }
165 int cntH = 0;
166 for (const auto& vn : vecNames) {
167 LOGP(info, "Loading external HistoManager {}", vn);
168 mHManV.emplace_back() = std::make_unique<o2::HistoManager>("", vn, true);
169 auto hm = mHManV.back().get();
170 if (!hm) {
171 LOGP(error, "Failed to load histograms from {}", vn);
172 mHManV.pop_back();
173 } else {
174 hm->SetName(useLeg ? vecLegends[cntH].c_str() : vn.c_str());
175 }
176 cntH++;
177 }
178 }
179 if (mDrawOnly) {
180 return;
181 }
183#ifndef WITH_OPENMP
184 if (mNThreads > 1) {
185 LOGP(warn, "No OpenMP");
186 }
187 mNThreads = 1;
188#endif
189 if (mFillTree) {
190 mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>(fmt::format("{}.root", params.outname).c_str(), "recreate");
191 }
192}
193
195{
196 bool quit = false;
197 if (mPostProcOnly) {
198
199 postProcessHistos();
200 quit = true;
201 }
202 if (mDrawOnly) {
203 drawHistos();
204 quit = true;
205 }
206 if (quit) {
207 if (mPostProcOnly && o2::checkresid::CheckResidConfig::Instance().savePostprocessed) {
208 for (const auto& hm : mHManV) {
209 if (hm) {
210 hm->write();
211 }
212 }
213 }
215 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
216 return;
217 }
219 mRecoData = &recoData;
220 mRecoData->collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer
221 mRecoData = &recoData;
222 updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions
223 process();
224 mRecoData = nullptr;
225}
226
227void CheckResidSpec::updateTimeDependentParams(ProcessingContext& pc)
228{
231 static bool initOnceDone = false;
232 if (!initOnceDone) { // this params need to be queried only once
234 initOnceDone = true;
235 // Note: reading of the ITS AlpideParam needed for ITS timing is done by the RecoContainer
238 if (!grp->isDetContinuousReadOut(DetID::ITS)) {
239 mITSROFrameLengthMUS = alpParams.roFrameLengthTrig / 1.e3; // ITS ROFrame duration in \mus
240 } else {
241 mITSROFrameLengthMUS = alpParams.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS * 1e-3; // ITS ROFrame duration in \mus
242 }
244 geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G, o2::math_utils::TransformType::T2G));
245 o2::conf::ConfigurableParam::updateFromString("pvertexer.useTimeInChi2=false;");
246 mVertexer.init();
247 }
248 if (mMeanVertexUpdated) {
249 mMeanVertexUpdated = false;
250 mVertexer.setMeanVertex(&mMeanVtx);
251 mVertexer.initMeanVertexConstraint();
252 }
253}
254
256{
257 if (!mITSDict) {
258 LOGP(fatal, "ITS data is not loaded");
259 }
260 const auto itsTracks = mRecoData->getITSTracks();
261 // const auto itsLbls = mRecoData->getITSTracksMCLabels();
262 const auto itsClRefs = mRecoData->getITSTracksClusterRefs();
264 int nLr = mDataRequest->getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1;
265 mITSClustersArray.init(nLr);
266 mITSClusterSizes.clear();
267 for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0
268 mITSClustersArray.beginLayer(lr);
269 const auto clusITS = mRecoData->getITSClusters(lr);
270 auto pattIt = mRecoData->getITSClustersPatterns(lr).begin();
271 {
272 auto sizePattIt = mRecoData->getITSClustersPatterns(lr).begin();
273 mITSClustersArray.getClusters().reserve(mITSClustersArray.size() + clusITS.size());
274 mITSClusterSizes.reserve(mITSClusterSizes.size() + clusITS.size());
275 for (const auto& clu : clusITS) {
276 const auto pattID = clu.getPatternID();
277 if (pattID == o2::itsmft::CompCluster::InvalidPatternID || mITSDict->isGroup(pattID)) {
278 o2::itsmft::ClusterPattern patt(sizePattIt);
279 mITSClusterSizes.emplace_back(patt.getNPixels());
280 } else {
281 mITSClusterSizes.emplace_back(mITSDict->getNpixels(pattID));
282 }
283 }
284 }
285 o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray.getClusters(), mITSDict);
286 }
287 mITSClustersArray.finalize();
288
289 auto pvvec = mRecoData->getPrimaryVertices();
290 auto trackIndex = mRecoData->getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks
291 auto vtxRefs = mRecoData->getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs
292 auto prop = o2::base::Propagator::Instance();
293 static int TFCount = 0;
294 int nv = vtxRefs.size() - 1;
295 std::vector<std::vector<checkresid::Track>> slots;
296 mPVUsed.clear();
297 slots.resize(mNThreads);
298 int nvGood = 0, nvUse = 0, nvRefFail = 0;
299 long pvFitDuration{};
300 for (int iv = 0; iv < nv; iv++) {
301 const auto& vtref = vtxRefs[iv];
302 auto pve = pvvec[iv];
303 if (pve.getNContributors() < params.minPVContributors) {
304 continue;
305 }
306 nvGood++;
307 if (params.refitPV) {
308 LOGP(debug, "Refitting PV#{} of {} tracks", iv, pve.getNContributors());
309 auto tStartPVF = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
310 bool res = refitPV(pve, iv);
311 pvFitDuration += std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count() - tStartPVF;
312 if (!res) {
313 nvRefFail++;
314 continue;
315 }
316 }
317 nvUse++;
318 mPVUsed.push_back(pve);
319 const auto& itsContRefs = vtref.getITSGloContributors();
320 int idMinITSGlo = 0, idMaxITSGlo = 0;
321 if (params.useITSGloContributors) {
322 if (itsContRefs.getFirstEntry() < vtref.getEntries() && itsContRefs.getEntries() == 0) {
323 LOGP(fatal, "Usage of stored ITS global contributors is requested but they are missing");
324 }
325 idMinITSGlo = itsContRefs.getFirstEntry();
326 idMaxITSGlo = idMinITSGlo + itsContRefs.getEntries();
327 }
328 int cntPVCont = 0;
329 for (int is = 0; is < GTrackID::NSources; is++) {
330 if (!params.useITSGloContributors && (!mTracksSrc[is] || !mRecoData->isTrackSourceLoaded(is))) {
331 continue;
332 }
333 int idMin = vtref.getFirstEntryOfSource(is), idMax = idMin + vtref.getEntriesOfSource(is);
334 DetID::mask_t dm = GTrackID::getSourceDetectorsMask(is);
335 if (!dm[DetID::ITS]) {
336 continue;
337 }
338#ifdef WITH_OPENMP
339#pragma omp parallel for schedule(dynamic) num_threads(mNThreads)
340#endif
341 for (int i = idMin; i < idMax; i++) {
342 auto vid = trackIndex[i];
343 bool pvCont = vid.isPVContributor();
344 if (!pvCont && (params.pvcontribOnly || params.useITSGloContributors)) {
345 continue;
346 }
347 GTrackID gidITS;
348 o2::track::PID pidITS;
349 if (params.useITSGloContributors) {
350 int id = idMinITSGlo + cntPVCont;
351 if (id >= idMaxITSGlo) {
352 LOGP(fatal, "Calculated GlobalContributor ITS track index {} exceeds number of stored indices {}", id, itsContRefs.getEntries());
353 }
354 pidITS = trackIndex[id].getSource();
355 gidITS = GTrackID(trackIndex[id].getIndex(), GTrackID::ITS);
356 cntPVCont++;
357 } else {
358 gidITS = mRecoData->getITSContributorGID(vid);
359 if (gidITS.getSource() != GTrackID::ITS) {
360 continue;
361 }
362 }
363 const auto& itsTrack = mRecoData->getITSTrack(gidITS);
364 if (itsTrack.getNClusters() < params.minITSCl) {
365 continue;
366 }
367 const auto& trc = params.useITSGloContributors ? ((o2::track::TrackParCov&)itsTrack) : mRecoData->getTrackParam(vid);
368 if (!params.useITSGloContributors) {
369 pidITS = trc.getPID();
370 }
371 auto pt = trc.getPt();
372 if (pt < params.minPt || pt > params.maxPt) {
373 continue;
374 }
375 if (std::abs(trc.getTgl()) > params.maxTgl) {
376 continue;
377 }
378#ifdef WITH_OPENMP
379 auto& accum = slots[omp_get_thread_num()];
380#else
381 auto& accum = slots[0];
382#endif
383 auto& resTrack = accum.emplace_back();
384 resTrack.gid = vid;
385 if (!processITSTrack(itsTrack, pve, resTrack, pidITS)) {
386 accum.pop_back();
387 continue;
388 }
389 }
390 }
391 }
392 // output
393 for (const auto& accum : slots) {
394 for (const auto& tr : accum) {
395 if (mDBGOut) {
396 (*mDBGOut) << "res" << "tr=" << tr << "\n";
397 }
398 if (mHMan) {
399 fillHistos(tr);
400 }
401 }
402 }
403 if (mDBGOut) {
404 (*mDBGOut) << "pvUsed" << "pv=" << mPVUsed << "\n";
405 }
406 if (mHMan) {
407 for (const auto& pv : mPVUsed) {
408 mHMan->getHisto(20000 + 0)->Fill(pv.getX());
409 mHMan->getHisto(20000 + 1)->Fill(pv.getY());
410 mHMan->getHisto(20000 + 2)->Fill(pv.getZ());
411 mHMan->getHisto(20000 + 3)->Fill(pv.getNContributors());
412 }
413 }
414 LOGP(info, "processed {} PVs out of {} good vertices (out of {} in total), PV refits took {} mus, {} refits failed", nvUse, nvGood, nv, pvFitDuration, nvRefFail);
415 TFCount++;
416}
417
418bool CheckResidSpec::processITSTrack(const o2::its::TrackITS& iTrack, const o2::dataformats::PrimaryVertex& pv, o2::checkresid::Track& resTrack, o2::track::PID pid)
419{
420 const auto itsClRefs = mRecoData->getITSTracksClusterRefs();
421 auto trFitInw = iTrack.getParamOut(); // seed for inward refit
422 auto trFitOut = iTrack.getParamIn(); // seed for outward refit
423 trFitInw.setPID(pid);
424 trFitOut.setPID(pid);
425 auto prop = o2::base::Propagator::Instance();
427 float pvAlpha = 0;
428 float bz = prop->getNominalBz();
429 std::array<const o2::BaseCluster<float>*, 8> clArr{};
430 std::array<int16_t, 8> clSizeArr{};
431 const auto& params = CheckResidConfig::Instance();
432 std::array<o2::track::TrackParCov, 8> extrapOut, extrapInw; // 2-way Kalman extrapolations, vertex + 7 layers
433 o2::track::TrackParCov trIBOutForIOB, trOBInwForIOB; // IB/OB sub-tracks (pre-R12 state) used for IOB residuals
434
435 auto rotateTrack = [bz](o2::track::TrackParCov& tr, float alpha, o2::track::TrackPar* refLin) {
436 return refLin ? tr.rotate(alpha, *refLin, bz) : tr.rotate(alpha);
437 };
438
439 auto accountCluster = [&](int i, std::array<o2::track::TrackParCov, 8>& extrapDest, o2::track::TrackParCov& tr, o2::track::TrackPar* refLin) {
440 if (clArr[i]) { // update with cluster
441 if (!rotateTrack(tr, i == 0 ? pvAlpha : geom->getSensorRefAlpha(clArr[i]->getSensorID()), refLin) ||
442 !prop->propagateTo(tr, refLin, clArr[i]->getX(), true)) {
443 return 0;
444 }
445 extrapDest[i] = tr; // before update
446 if (!tr.update(*clArr[i])) {
447 return 0;
448 }
449 } else {
450 extrapDest[i].invalidate();
451 return -1;
452 }
453 return 1;
454 };
455
456 auto inv2d = [](float s00, float s11, float s01) -> std::array<float, 3> {
457 auto det = s00 * s11 - s01 * s01;
458 if (det < 1e-16) {
459 LOGP(error, "Singular det {}, input: {} {} {}", det, s00, s11, s01);
460 return {0.f, 0.f, 0.f};
461 }
462 det = 1.f / det;
463 return {s11 * det, s00 * det, -s01 * det};
464 };
465
466 resTrack.points.clear();
467 if (!prop->propagateToDCA(pv, trFitOut, bz)) {
468 LOGP(debug, "Failed to propagateToDCA, {}", trFitOut.asString());
469 return false;
470 }
472 if (params.addPVAsCluster) {
473 float cosAlp, sinAlp;
474 pvAlpha = trFitOut.getAlpha();
475 o2::math_utils::sincos(trFitOut.getAlpha(), sinAlp, cosAlp); // vertex position rotated to track frame
476 bcPV.setXYZ(pv.getX() * cosAlp + pv.getY() * sinAlp, -pv.getX() * sinAlp + pv.getY() * cosAlp, pv.getZ());
477 bcPV.setSigmaY2(0.5 * (pv.getSigmaX2() + pv.getSigmaY2()));
478 bcPV.setSigmaZ2(pv.getSigmaZ2());
479 bcPV.setSensorID(-1);
480 clArr[0] = &bcPV;
481 }
482 // collect all track clusters to array, placing them to layer+1 slot
483 int nCl = iTrack.getNClusters();
484 for (int i = 0; i < nCl; i++) { // clusters are ordered from the outermost to the innermost
485 const auto& curClu = mITSClustersArray[itsClRefs[iTrack.getClusterEntry(i)]];
486
487 int llr = geom->getLayer(curClu.getSensorID());
488 if (clArr[1 + llr]) {
489 LOGP(error, "Cluster at lr {} was already assigned, old sens {}, new sens {}", llr, clArr[1 + llr]->getSensorID(), curClu.getSensorID());
490 }
491 clArr[1 + geom->getLayer(curClu.getSensorID())] = &curClu;
492 clSizeArr[1 + geom->getLayer(curClu.getSensorID())] = mITSClusterSizes[itsClRefs[iTrack.getClusterEntry(i)]];
493 }
494 o2::track::TrackPar refLinInw0, refLinOut0, *refLinOut = nullptr, *refLinInw = nullptr;
495 o2::track::TrackPar refLinIBOut0, refLinOBInw0, *refLinOBInw = nullptr, *refLinIBOut = nullptr;
496 if (params.useStableRef) {
497 refLinOut = &(refLinOut0 = trFitOut);
498 refLinInw = &(refLinInw0 = trFitInw);
499 }
500 trFitOut.resetCovariance();
501 trFitOut.setCov(trFitOut.getQ2Pt() * trFitOut.getQ2Pt() * trFitOut.getCov()[14], 14);
502 trFitInw.resetCovariance();
503 trFitInw.setCov(trFitInw.getQ2Pt() * trFitInw.getQ2Pt() * trFitInw.getCov()[14], 14);
504 // fit in inward and outward direction
505 for (int i = 0; i <= 7; i++) {
506 int resOut, resInw;
507 // process resOut in ascending order (0-->7) and resInw in descending order (7-->0)
508 if (!(resOut = accountCluster(i, extrapOut, trFitOut, refLinOut)) || !(resInw = accountCluster(7 - i, extrapInw, trFitInw, refLinInw))) {
509 return false;
510 }
511 // at layer 3, find the IB track (trIBOut) and the OB track (trOBInw)
512 // propagate both trcaks to a common radius, RCompIBOB (12cm), and rotates
513 // them to the same reference frame for comparison
514 if (i == 3 && resOut == 1 && resInw == 1 && (params.doIBOB || params.doIBOBresiduals) && nCl == 7) {
515 if (params.doIBOBresiduals) { // keep the un-rotated IB/OB sub-tracks for the per-layer IOB residuals below
516 trIBOutForIOB = trFitOut;
517 trOBInwForIOB = trFitInw;
518 }
519 resTrack.trIBOut = trFitOut; // outward track updated at outermost IB layer
520 resTrack.trOBInw = trFitInw; // inward track updated at innermost OB layer
521 o2::track::TrackPar refLinIBOut0, refLinIBIn0;
522 if (refLinOut) {
523 refLinIBOut = &(refLinIBOut0 = refLinOut0);
524 refLinOBInw = &(refLinOBInw0 = refLinInw0);
525 }
526 float xRref;
527 if (!resTrack.trOBInw.getXatLabR(params.rCompIBOB, xRref, bz) ||
528 !prop->propagateTo(resTrack.trOBInw, refLinOBInw, xRref, true) ||
529 !rotateTrack(resTrack.trOBInw, resTrack.trOBInw.getPhiPos(), refLinOBInw) || // propagate OB track to ref R and rotate
530 !rotateTrack(resTrack.trIBOut, resTrack.trOBInw.getAlpha(), refLinIBOut) ||
531 !prop->propagateTo(resTrack.trIBOut, refLinIBOut, resTrack.trOBInw.getX(), true)) { // rotate OB track to same frame and propagate to same X
532 // if any propagation or rotation steps fail, invalidate both tracks
533 return false;
534 }
535 }
536 }
537
538 // extrapolate the IB(OB) sub-track, w/o intermediate updates, to the cluster (or PV pseudo-cluster) of an OB(IB) layer, for the IOB residuals
539 auto extrapIOB = [&](const o2::track::TrackParCov& srcTr, int i) -> std::array<float, 4> { // {dy, dz, sig2y, sig2z}, sig2y<=0 : invalid
540 o2::track::TrackParCov tr = srcTr;
541 auto alpha = i == 0 ? pvAlpha : geom->getSensorRefAlpha(clArr[i]->getSensorID());
542 if (!rotateTrack(tr, alpha, nullptr) || !prop->propagateTo(tr, nullptr, clArr[i]->getX(), true)) {
543 return {0.f, 0.f, 0.f, 0.f};
544 }
545 return {clArr[i]->getY() - tr.getY(), clArr[i]->getZ() - tr.getZ(), tr.getSigmaY2() + clArr[i]->getSigmaY2(), tr.getSigmaZ2() + clArr[i]->getSigmaZ2()};
546 };
547 bool haveIOBTracks = params.doIBOBresiduals && nCl == 7 && trIBOutForIOB.getX() > 1 && trOBInwForIOB.getX() > 1;
548
549 bool innerDone = false;
550 if (params.doResid) {
551 for (int i = 0; i <= 7; i++) {
552 if (clArr[i]) {
553 // calculate interpolation as a weighted mean of inward/outward extrapolations to this layer
554 const auto &tInw = extrapInw[i], &tOut = extrapOut[i];
555 auto wInw = inv2d(tInw.getSigmaY2(), tInw.getSigmaZ2(), tInw.getSigmaZY());
556 auto wOut = inv2d(tOut.getSigmaY2(), tOut.getSigmaZ2(), tOut.getSigmaZY());
557 if (wInw[0] == 0.f || wOut[0] == 0.f) {
558 return false;
559 }
560 std::array<float, 3> wTot = {wInw[0] + wOut[0], wInw[1] + wOut[1], wInw[2] + wOut[2]};
561 auto cTot = inv2d(wTot[0], wTot[1], wTot[2]);
562 auto ywi = wInw[0] * tInw.getY() + wInw[2] * tInw.getZ() + wOut[0] * tOut.getY() + wOut[2] * tOut.getZ();
563 auto zwi = wInw[2] * tInw.getY() + wInw[1] * tInw.getZ() + wOut[2] * tOut.getY() + wOut[1] * tOut.getZ();
564 auto yw = ywi * cTot[0] + zwi * cTot[2];
565 auto zw = ywi * cTot[2] + zwi * cTot[1];
566 // posCl.push_back(clArr[i]->getXYZGlo(*o2::its::GeometryTGeo::Instance()));
567 auto phi = i == 0 ? tInw.getPhi() : tInw.getPhiPos();
568 o2::math_utils::bringTo02Pi(phi);
569 std::array<float, 4> iob{0.f, 0.f, 0.f, 0.f};
570 if (haveIOBTracks) {
571 int lr = i - 1; // -1 = vertex
572 if (lr <= 2) { // vertex or IB layer: extrapolate the OB sub-track to it (the vertex constrains the IB outward fit)
573 iob = extrapIOB(trOBInwForIOB, i);
574 } else { // OB layer: extrapolate the IB sub-track to it
575 iob = extrapIOB(trIBOutForIOB, i);
576 }
577 }
578 resTrack.points.emplace_back(clArr[i]->getY() - yw, clArr[i]->getZ() - zw, cTot[0] + clArr[i]->getSigmaY2(), cTot[1] + clArr[i]->getSigmaZ2(),
579 iob[0], iob[1], iob[2], iob[3], phi, clArr[i]->getZ(), 0.5 * (tInw.getSnp() + tOut.getSnp()), clSizeArr[i], clArr[i]->getSensorID(), i - 1);
580 if (!innerDone) {
581 resTrack.track = tInw;
582 innerDone = true;
583 }
584 } else {
585 LOGP(debug, "No cluster on lr {}", i);
586 }
587 }
588 }
589 return true;
590}
591
592bool CheckResidSpec::refitPV(o2::dataformats::PrimaryVertex& pv, int vid)
593{
595 std::vector<o2::track::TrackParCov> tracks;
596 std::vector<bool> useTrack;
597 std::vector<GTrackID> gidsITS;
598 int ntr = pv.getNContributors(), ntrIni = ntr;
599 tracks.reserve(ntr);
600 useTrack.reserve(ntr);
601 gidsITS.reserve(ntr);
602 const auto& vtref = mRecoData->getPrimaryVertexMatchedTrackRefs()[vid];
603 auto trackIndex = mRecoData->getPrimaryVertexMatchedTracks();
604 const auto& itsContRefs = vtref.getITSGloContributors();
605 if (params.useITSGloContributors && itsContRefs.getEntries()) {
606 int itr = itsContRefs.getFirstEntry(), itLim = itr + itsContRefs.getEntries();
607 for (; itr < itLim; itr++) {
608 auto tid = trackIndex[itr]; // these are ITS tracks, the Source part is substituted by the PID!!!
609 tracks.emplace_back().setPID(tid.getSource());
610 gidsITS.emplace_back(tid.getIndex(), GTrackID::ITS);
611 }
612 } else {
613 int itr = vtref.getFirstEntry(), itLim = itr + vtref.getEntries();
614 for (; itr < itLim; itr++) {
615 auto tid = trackIndex[itr];
616 if (tid.isPVContributor() && mRecoData->isTrackSourceLoaded(tid.getSource())) {
617 tracks.emplace_back().setPID(mRecoData->getTrackParam(tid).getPID());
618 gidsITS.push_back(mRecoData->getITSContributorGID(tid));
619 }
620 }
621 }
622 ntr = tracks.size();
623 useTrack.resize(ntr);
624#ifdef WITH_OPENMP
625#pragma omp parallel for schedule(dynamic) num_threads(mNThreads)
626#endif
627 for (int itr = 0; itr < ntr; itr++) {
628 if (!(useTrack[itr] = refitITStrack(tracks[itr], gidsITS[itr]))) {
629 tracks[itr] = mRecoData->getTrackParam(gidsITS[itr]); // this track will not be used but participates in prepareVertexRefit
630 }
631 }
632 ntr = 0;
633 for (auto v : useTrack) {
634 ntr++;
635 }
636 if (ntr < params.minPVContributors || !mVertexer.prepareVertexRefit(tracks, pv)) {
637 LOGP(warn, "Abandon vertex refit: NcontribNew = {} vs NcontribOld = {}", ntr, ntrIni);
638 return false;
639 }
640 LOGP(debug, "Original vtx: Nc:{} {}, chi2={}", pv.getNContributors(), pv.asString(), pv.getChi2());
641 auto pvSave = pv;
642 pv = mVertexer.refitVertexFull(useTrack, pv);
643 LOGP(debug, "Refitted vtx: Nc:{} {}, chi2={}", ntr, pv.asString(), pv.getChi2());
644 if (pv.getChi2() < 0.f) {
645 LOGP(warn, "Failed to refit PV {}", pvSave.asString());
646 return false;
647 }
648 return true;
649}
650
651bool CheckResidSpec::refitITStrack(o2::track::TrackParCov& track, GTrackID gid)
652{
653 // destination tack might have non-default PID assigned
654 const auto& trkITS = mRecoData->getITSTrack(gid);
655 const auto itsClRefs = mRecoData->getITSTracksClusterRefs();
656 const auto& params = CheckResidConfig::Instance();
657 auto pid = track.getPID();
658 track = trkITS.getParamOut();
659 track.resetCovariance();
660 track.setCov(track.getQ2Pt() * track.getQ2Pt() * track.getCov()[14], 14);
661 track.setPID(pid);
662 auto nCl = trkITS.getNumberOfClusters();
664 auto prop = o2::base::Propagator::Instance();
665 float bz = prop->getNominalBz();
667
668 for (int iCl = 0; iCl < nCl; iCl++) { // clusters are stored from outer to inner layers
669 const auto& cls = mITSClustersArray[itsClRefs[trkITS.getClusterEntry(iCl)]];
670 auto alpha = geom->getSensorRefAlpha(cls.getSensorID());
671 if (!(params.useStableRef ? track.rotate(alpha, refLin, bz) : track.rotate(alpha)) ||
672 !prop->propagateTo(track, params.useStableRef ? &refLin : nullptr, cls.getX(), true)) {
673 LOGP(debug, "refitITStrack failed on propagation to cl#{}, alpha={}, x={} | {}", iCl, alpha, cls.getX(), track.asString());
674 return false;
675 }
676 if (!track.update(cls)) {
677 LOGP(debug, "refitITStrack failed on update with cl#{}, | {}", iCl, track.asString());
678 return false;
679 }
680 }
681 return true;
682}
683
684void CheckResidSpec::fillHistos(const o2::checkresid::Track& trc)
685{
686 const auto& params = CheckResidConfig::Instance();
688 int np = trc.points.size();
689 auto pt = trc.track.getPt();
690 if (pt < params.minPt || pt > params.maxPt) {
691 return;
692 }
693 auto tgl = trc.track.getTgl();
694 // fills, for a given id offset, the dy/dz (+pull) vs phi/Z/pT/tgl histos of layer slot il
695 auto fillLayerResid = [&](int idOffset, int il, float phi, float z, float dy, float dz, float sig2y, float sig2z) {
696 mHMan->getHisto2F(idOffset + il * 10 + 0 * 100)->Fill(phi, dy);
697 mHMan->getHisto2F(idOffset + il * 10 + 0 * 100 + 1000)->Fill(z, dy);
698 mHMan->getHisto2F(idOffset + il * 10 + 0 * 100 + 2000)->Fill(pt, dy);
699 mHMan->getHisto2F(idOffset + il * 10 + 0 * 100 + 3000)->Fill(tgl, dy);
700 if (sig2y > 0) {
701 auto pull = dy / std::sqrt(sig2y);
702 mHMan->getHisto2F(idOffset + il * 10 + 0 * 100 + 5)->Fill(phi, pull);
703 mHMan->getHisto2F(idOffset + il * 10 + 0 * 100 + 5 + 1000)->Fill(z, pull);
704 mHMan->getHisto2F(idOffset + il * 10 + 0 * 100 + 5 + 2000)->Fill(pt, pull);
705 mHMan->getHisto2F(idOffset + il * 10 + 0 * 100 + 5 + 3000)->Fill(tgl, pull);
706 }
707 mHMan->getHisto2F(idOffset + il * 10 + 1 * 100)->Fill(phi, dz);
708 mHMan->getHisto2F(idOffset + il * 10 + 1 * 100 + 1000)->Fill(z, dz);
709 mHMan->getHisto2F(idOffset + il * 10 + 1 * 100 + 2000)->Fill(pt, dz);
710 mHMan->getHisto2F(idOffset + il * 10 + 1 * 100 + 3000)->Fill(tgl, dz);
711 if (sig2z > 0) {
712 auto pull = dz / std::sqrt(sig2z);
713 mHMan->getHisto2F(idOffset + il * 10 + 1 * 100 + 5)->Fill(phi, pull);
714 mHMan->getHisto2F(idOffset + il * 10 + 1 * 100 + 5 + 1000)->Fill(z, pull);
715 mHMan->getHisto2F(idOffset + il * 10 + 1 * 100 + 5 + 2000)->Fill(pt, pull);
716 mHMan->getHisto2F(idOffset + il * 10 + 1 * 100 + 5 + 3000)->Fill(tgl, pull);
717 }
718 };
719 // fills, for a given id offset, the per-chip dy/dz (+pull) histo of a layer point on sensor sens
720 auto fillChipResid = [&](int idOffset, int il, int lr, int sens, float dy, float dz, float sig2y, float sig2z) {
721 if (sens >= 0 && geom->getLayer(sens) == lr) {
722 const int halfBarrel = geom->getHalfBarrel(sens);
723 const int chip = geom->getFirstChipIndex(lr) + geom->getChipIdInLayer(sens);
724 const int chipHistoID = idOffset + (2 * il + halfBarrel) * 100 + 15000;
725 if (halfBarrel >= 0 && halfBarrel < 2) {
726 mHMan->getHisto2F(chipHistoID)->Fill(chip, dy);
727 mHMan->getHisto2F(chipHistoID + 10)->Fill(chip, dz);
728 if (sig2y > 0) {
729 mHMan->getHisto2F(chipHistoID + 5)->Fill(chip, dy / std::sqrt(sig2y));
730 }
731 if (sig2z > 0) {
732 mHMan->getHisto2F(chipHistoID + 15)->Fill(chip, dz / std::sqrt(sig2z));
733 }
734 }
735 }
736 };
737
738 for (int ip = 0; ip < np; ip++) {
739 const auto& pnt = trc.points[ip];
740 int il = pnt.lr >= 0 ? pnt.lr + 1 : 0;
741 fillLayerResid(0, il, pnt.phi, pnt.z, pnt.dy, pnt.dz, pnt.sig2y, pnt.sig2z);
742 if (pnt.lr >= 0) {
743 fillChipResid(0, il, pnt.lr, pnt.sens, pnt.dy, pnt.dz, pnt.sig2y, pnt.sig2z);
744 }
745 if (pnt.sig2yIOB > 0) { // IOB residual was computed for this point
746 fillLayerResid(100000, il, pnt.phi, pnt.z, pnt.dyIOB, pnt.dzIOB, pnt.sig2yIOB, pnt.sig2zIOB);
747 if (pnt.lr >= 0) {
748 fillChipResid(100000, il, pnt.lr, pnt.sens, pnt.dyIOB, pnt.dzIOB, pnt.sig2yIOB, pnt.sig2zIOB);
749 }
750 }
751 }
752 //--------------
753 if (trc.trIBOut.getX() > 1 && std::abs(trc.trIBOut.getX() - trc.trOBInw.getX()) < 0.1) {
754 for (int ip = 0; ip < 5; ip++) {
755 float d = trc.trIBOut.getParam(ip) - trc.trOBInw.getParam(ip);
756 mHMan->getHisto2F(10000 + ip * 10)->Fill(trc.trIBOut.getPhiPos(), d);
757 mHMan->getHisto2F(11000 + ip * 10)->Fill(trc.trIBOut.getZ(), d);
758 mHMan->getHisto2F(12000 + ip * 10)->Fill(pt, d);
759 mHMan->getHisto2F(13000 + ip * 10)->Fill(trc.track.getTgl(), d);
760 float sg = trc.trIBOut.getCovarElem(ip, ip) + trc.trOBInw.getCovarElem(ip, ip);
761 if (sg > 0) {
762 auto pull = d / std::sqrt(sg);
763 mHMan->getHisto2F(10000 + ip * 10 + 5)->Fill(trc.trIBOut.getPhiPos(), pull);
764 mHMan->getHisto2F(11000 + ip * 10 + 5)->Fill(trc.trIBOut.getZ(), pull);
765 mHMan->getHisto2F(12000 + ip * 10 + 5)->Fill(pt, pull);
766 mHMan->getHisto2F(13000 + ip * 10 + 5)->Fill(trc.track.getTgl(), pull);
767 }
768 }
769 }
770}
771
772void CheckResidSpec::bookHistos()
773{
775 mHManV.emplace_back() = std::make_unique<o2::HistoManager>("", fmt::format("{}_hman.root", params.outname));
776 mHMan = mHManV.back().get();
777 mHMan->SetName(params.outname.c_str());
778 auto defLogAxis = [](float xMn, float xMx, int nbin) { // get array for log axis
779 if (xMn <= 0 || xMx <= xMn || nbin < 2) {
780 LOGP(fatal, "Wrong log axis request: xmin = {} xmax = {} nbins = {}", xMn, xMx, nbin);
781 }
782 auto dx = std::log(xMx / xMn) / nbin;
783 std::vector<double> xax(nbin + 1);
784 for (int i = 0; i <= nbin; i++) {
785 xax[i] = xMn * std::exp(dx * i);
786 }
787 return xax;
788 };
789 float minPt = std::max(0.1f, params.minPt), maxPt = std::min(50.f, params.maxPt);
790 auto ptax = defLogAxis(minPt, maxPt, params.nBinsPt);
791
792 // books, for a given id offset (0 for the standard layer residuals, 100000 for the IOB ones) and name/title suffix,
793 // the dy/dz (+pull) vs phi/Z/pT/tgl histos and the per-chip histos; bookVtx controls whether the vtx (il=0) slot is booked
794 auto bookLayerResidHistos = [&](int idOffset, const std::string& suf, bool bookVtx) {
795 const float dyzScale = idOffset ? params.IOBScaleFactor : 1.f; // IOB residuals have a much larger range than the standard ones
796 for (int il = bookVtx ? 0 : 1; il < 8; il++) {
797 std::string lrName = il == 0 ? "Vtx" : fmt::format("Lr{}", il - 1);
798 const float maxDYZ = params.maxDYZ[il] * dyzScale;
799 for (int iyz = 0; iyz < 2; iyz++) {
800 std::string dname = fmt::format("{}{}", iyz == 0 ? "dy" : "dz", suf), dtit = fmt::format("{}{}", iyz == 0 ? "#DeltaY" : "#DeltaZ", suf.empty() ? "" : ("_" + suf));
801 auto h2 = new TH2F(fmt::format("{}_{}_{}", dname, lrName, "phi").c_str(), fmt::format("{}_{{{}}} vs {};#phi;{}", dtit, lrName, "#phi", dtit).c_str(), params.nBinsPhi, 0, TMath::Pi() * 2, params.nBinsRes, -maxDYZ, maxDYZ);
802 mHMan->addHisto(h2, idOffset + il * 10 + iyz * 100);
803 auto h2p = new TH2F(fmt::format("{}_{}_{}_pull", dname, lrName, "phi").c_str(), fmt::format("pull {}_{{{}}} vs {};#phi; pull{}", dtit, lrName, "phi", dtit).c_str(), params.nBinsPhi, 0, TMath::Pi() * 2, params.nBinsRes, -params.maxPull, params.maxPull);
804 mHMan->addHisto(h2p, idOffset + il * 10 + iyz * 100 + 5);
805
806 auto hz2 = new TH2F(fmt::format("{}_{}_{}", dname, lrName, "Z").c_str(), fmt::format("{}_{{{}}} vs {};Z;{}", dtit, lrName, "Z", dtit).c_str(), params.nBinsZ, -params.zranges[il], params.zranges[il], params.nBinsRes, -maxDYZ, maxDYZ);
807 mHMan->addHisto(hz2, idOffset + il * 10 + iyz * 100 + 1000);
808 auto hz2p = new TH2F(fmt::format("{}_{}_{}_pull", dname, lrName, "Z").c_str(), fmt::format("pull {}_{{{}}} vs {};Z; pull{}", dtit, lrName, "Z", dtit).c_str(), params.nBinsZ, -params.zranges[il], params.zranges[il], params.nBinsRes, -params.maxPull, params.maxPull);
809 mHMan->addHisto(hz2p, idOffset + il * 10 + iyz * 100 + 5 + 1000);
810
811 auto hpt2 = new TH2F(fmt::format("{}_{}_{}", dname, lrName, "Pt").c_str(), fmt::format("{}_{{{}}} vs {};p_{{T}};{}", dtit, lrName, "p_{T}", dtit).c_str(), params.nBinsPt, ptax.data(), params.nBinsRes, -maxDYZ, maxDYZ);
812 mHMan->addHisto(hpt2, idOffset + il * 10 + iyz * 100 + 2000);
813 auto hpt2p = new TH2F(fmt::format("{}_{}_{}_pull", dname, lrName, "Pt").c_str(), fmt::format("pull {}_{{{}}} vs {};p_{{T}}; pull{}", dtit, lrName, "p_{T}", dtit).c_str(), params.nBinsPt, ptax.data(), params.nBinsRes, -params.maxPull, params.maxPull);
814 mHMan->addHisto(hpt2p, idOffset + il * 10 + iyz * 100 + 5 + 2000);
815
816 auto htgl2 = new TH2F(fmt::format("{}_{}_{}", dname, lrName, "tgl").c_str(), fmt::format("{}_{{{}}} vs {};tg#lambda;{}", dtit, lrName, "tg#lambda", dtit).c_str(), params.nBinsTgl, -params.maxTgl, params.maxTgl, params.nBinsRes, -maxDYZ, maxDYZ);
817 mHMan->addHisto(htgl2, idOffset + il * 10 + iyz * 100 + 3000);
818 auto htgl2p = new TH2F(fmt::format("{}_{}_{}_pull", dname, lrName, "tgl").c_str(), fmt::format("pull {}_{{{}}} vs {};tg#lambda; pull{}", dtit, lrName, "tg#lambda", dtit).c_str(), params.nBinsTgl, -params.maxTgl, params.maxTgl, params.nBinsRes, -params.maxPull, params.maxPull);
819 mHMan->addHisto(htgl2p, idOffset + il * 10 + iyz * 100 + 5 + 3000);
820
821 if (il > 0) {
822 const int ilr = il - 1;
823 const int nChips = mChipMap.getNChipsOnLayer(ilr) / 2;
824 for (int ib = 0; ib < 2; ++ib) { // chips per halfbarrel
825 const int startChip = ib * nChips + mChipMap.getFirstChipsOnLayer(ilr);
826 auto hc2 = new TH2F(fmt::format("{}_{}_{}", dname, lrName, ib).c_str(), fmt::format("{} Lr{} HB{};chip;{}", dname, lrName, ib, dtit).c_str(), nChips, startChip - 0.5, startChip - 0.5 + nChips, params.nBinsRes, -maxDYZ, maxDYZ);
827 mHMan->addHisto(hc2, idOffset + (2 * il + ib) * 100 + iyz * 10 + 15000);
828 auto hc2p = new TH2F(fmt::format("{}_{}_{}_pull", dname, lrName, ib).c_str(), fmt::format("{} Lr{} HB{} pull;chip;pull{}", dname, lrName, ib, dtit).c_str(), nChips, startChip - 0.5, startChip - 0.5 + nChips, params.nBinsRes, -params.maxPull, params.maxPull);
829 mHMan->addHisto(hc2p, idOffset + (2 * il + ib) * 100 + iyz * 10 + 5 + 15000);
830 }
831 }
832 }
833 }
834 };
835 bookLayerResidHistos(0, "", true);
836 if (params.doIBOBresiduals) { // the vtx slot is included: the PV constrains the IB outward fit, so it gets an OB-extrapolated IOB residual too
837 bookLayerResidHistos(100000, "IOB", true);
838 }
839
840 for (int ip = 0; ip < 5; ip++) {
841 auto h2 = new TH2F(fmt::format("dPar{}_IBOBphi", ip).c_str(), fmt::format("#Delta par{} IB-OB vs phi;#phi;#Delta par{}", ip, ip).c_str(), params.nBinsPhi, 0, TMath::Pi() * 2, params.nBinsRes, -params.maxDPar[ip], params.maxDPar[ip]);
842 mHMan->addHisto(h2, 10000 + ip * 10);
843 auto h2p = new TH2F(fmt::format("dPar{}_IBOBphi_pull", ip).c_str(), fmt::format("pull #Delta par{} IB-OB vs phi;#phi;pull #Delta par{}", ip, ip).c_str(), params.nBinsPhi, 0, TMath::Pi() * 2, params.nBinsRes, -params.maxPull, params.maxPull);
844 mHMan->addHisto(h2p, 10000 + ip * 10 + 5);
845
846 auto hz2 = new TH2F(fmt::format("dPar{}_IBOBz", ip).c_str(), fmt::format("#Delta par{} IB-OB vs Z;Z;#Delta par{}", ip, ip).c_str(), params.nBinsZ, -20., 20., params.nBinsRes, -params.maxDPar[ip], params.maxDPar[ip]);
847 mHMan->addHisto(hz2, 11000 + ip * 10);
848 auto hz2p = new TH2F(fmt::format("dPar{}_IBOBz_pull", ip).c_str(), fmt::format("pull #Delta par{} IB-OB vs Z;Z;pull #Delta par{}", ip, ip).c_str(), params.nBinsZ, -20., 20., params.nBinsRes, -params.maxPull, params.maxPull);
849 mHMan->addHisto(hz2p, 11000 + ip * 10 + 5);
850
851 auto hpt2 = new TH2F(fmt::format("dPar{}_IBOBpt", ip).c_str(), fmt::format("#Delta par{} IB-OB vs pT;p_{{T}};#Delta par{}", ip, ip).c_str(), params.nBinsPt, ptax.data(), params.nBinsRes, -params.maxDPar[ip], params.maxDPar[ip]);
852 mHMan->addHisto(hpt2, 12000 + ip * 10);
853 auto hpt2p = new TH2F(fmt::format("dPar{}_IBOBpt_pull", ip).c_str(), fmt::format("pull #Delta par{} IB-OB vs pT;p_{{T}};pull #Delta par{}", ip, ip).c_str(), params.nBinsPt, ptax.data(), params.nBinsRes, -params.maxPull, params.maxPull);
854 mHMan->addHisto(hpt2p, 12000 + ip * 10 + 5);
855
856 auto htgl2 = new TH2F(fmt::format("dPar{}_IBOBtgl", ip).c_str(), fmt::format("#Delta par{} IB-OB vs tg#lambda;tg#lambda;#Delta par{}", ip, ip).c_str(), params.nBinsTgl, -params.maxTgl, params.maxTgl, params.nBinsRes, -params.maxDPar[ip], params.maxDPar[ip]);
857 mHMan->addHisto(htgl2, 13000 + ip * 10);
858 auto htgl2p = new TH2F(fmt::format("dPar{}_IBOBtgl_pull", ip).c_str(), fmt::format("pull #Delta par{} IB-OB vs tg#lambda;tg#lambda;pull #Delta par{}", ip, ip).c_str(), params.nBinsTgl, -params.maxTgl, params.maxTgl, params.nBinsRes, -params.maxPull, params.maxPull);
859 mHMan->addHisto(htgl2p, 13000 + ip * 10 + 5);
860 }
861 // used PV
862 mHMan->addHisto(new TH1F("pvX", "PV X;x;", params.nBinsPVXYZ, -params.maxHPVXY, params.maxHPVXY), 20000 + 0);
863 mHMan->addHisto(new TH1F("pvY", "PV Y;y;", params.nBinsPVXYZ, -params.maxHPVXY, params.maxHPVXY), 20000 + 1);
864 mHMan->addHisto(new TH1F("pvZ", "PV Z;z;", params.nBinsPVXYZ, -params.maxHPVZ, params.maxHPVZ), 20000 + 2);
865 mHMan->addHisto(new TH1F("pvN", "PV Contributors;Nc;", params.maxHPVN, 1.5, params.maxHPVN + 1.5), 20000 + 3);
866}
867
868void CheckResidSpec::postProcessHistos()
869{
870 printf("Fitting histos\n");
871 if (!mHMan) {
872 if (mHManV.empty()) {
873 LOGP(warn, "nothing to process");
874 return;
875 }
876 mHMan = mHManV[0].get();
877 }
879 auto gs = new TF1("gs", "gaus", -1, 1);
880 int maxH = mPostProcOnly ? mHManV.size() : 1;
881 TObjArray arr;
882 for (int ihm = 0; ihm < maxH; ihm++) {
883 auto* histm = mHManV[ihm].get();
884 if (!histm) {
885 continue;
886 }
887 auto fitSlices = [&](int id) {
888 auto h2 = histm->getHisto2F(id);
889 if (!h2 || h2->GetEntries() < params.minHistoStat2Fit) {
890 return;
891 }
892 h2->FitSlicesY(gs, 0, -1, 0, "QNR", &arr);
893 arr.SetOwner(true);
894 TH1* hmean = (TH1*)arr.RemoveAt(1);
895 if (hmean) {
896 hmean->SetTitle(Form("<%s>", h2->GetTitle()));
897 histm->addHisto(hmean, id + 1);
898 }
899 TH1* hsig = (TH1*)arr.RemoveAt(2);
900 if (hsig) {
901 hsig->SetTitle(Form("#sigma(%s)", h2->GetTitle()));
902 histm->addHisto(hsig, id + 2);
903 }
904 };
905 for (int ioffs = 0; ioffs <= 3; ioffs++) { // vs phi, Z, pT, tgl
906 int offs = ioffs * 1000;
907 for (int iht = 0; iht < 2; iht++) { // resid, pull
908 int offsV = iht == 0 ? 0 : 5;
909 for (int idOffset : {0, 100000}) { // standard and IOB residuals; fitSlices is a no-op if the histo was not booked
910 for (int il = 0; il < 8; il++) {
911 for (int iyz = 0; iyz < 2; iyz++) {
912 fitSlices(idOffset + il * 10 + iyz * 100 + offsV + offs);
913 }
914 }
915 }
916 for (int ip = 0; ip < 5; ip++) {
917 fitSlices(10000 + ip * 10 + offsV + offs);
918 }
919 }
920 }
921 for (int idOffset : {0, 100000}) {
922 for (int il = 1; il < 8; il++) {
923 for (int ib = 0; ib < 2; ib++) {
924 for (int iyz = 0; iyz < 2; iyz++) {
925 for (int iht = 0; iht < 2; iht++) {
926 const int offsV = iht == 0 ? 0 : 5;
927 fitSlices(idOffset + (2 * il + ib) * 100 + iyz * 10 + offsV + 15000);
928 }
929 }
930 }
931 }
932 }
933 }
934 delete gs;
935}
936
937void CheckResidSpec::drawHistos()
938{
939 // gROOT->SetBatch(true);
940 gStyle->SetTitleX(0.3);
941 gStyle->SetTitleY(0.88);
942 gStyle->SetTitleW(0.25);
943 gStyle->SetOptStat(0);
945 int nhm = mHManV.size();
946 std::array<unsigned int, 3> hcol{EColor::kRed, EColor::kBlue, EColor::kGreen + 2};
947 const auto hmNames = o2::utils::Str::tokenize(params.ext_hm_list, ",;");
948 const auto colorNames = o2::utils::Str::tokenize(params.ext_color_list, ",;");
949 const auto markerIDs = o2::utils::Str::tokenize(params.ext_marker_list, ",;");
950 bool useColors = colorNames.size() == hmNames.size() && !colorNames.empty();
951 bool useMarkers = markerIDs.size() == hmNames.size() && !markerIDs.empty();
952 if (!useColors) {
953 LOGP(warn, "{} color names provided for {} external histomanagers, will use automatic colors", colorNames.size(), hmNames.size());
954 }
955 if (!useMarkers) {
956 LOGP(warn, "{} marker IDs provided for {} external histomanagers, will use automatic markers", markerIDs.size(), hmNames.size());
957 }
958 constexpr std::array<std::pair<std::string_view, int>, 15> rootColors{{
959 {"kWhite", EColor::kWhite},
960 {"kBlack", EColor::kBlack},
961 {"kGray", EColor::kGray},
962 {"kRed", EColor::kRed},
963 {"kGreen", EColor::kGreen},
964 {"kBlue", EColor::kBlue},
965 {"kYellow", EColor::kYellow},
966 {"kMagenta", EColor::kMagenta},
967 {"kCyan", EColor::kCyan},
968 {"kOrange", EColor::kOrange},
969 {"kSpring", EColor::kSpring},
970 {"kTeal", EColor::kTeal},
971 {"kAzure", EColor::kAzure},
972 {"kViolet", EColor::kViolet},
973 {"kPink", EColor::kPink},
974 }};
975 auto parseColor = [&rootColors](const std::string& token) -> std::optional<int> {
976 std::string normalized;
977 normalized.reserve(token.size());
978 for (unsigned char ch : token) {
979 if (!std::isspace(ch)) {
980 normalized.push_back(ch);
981 }
982 }
983 for (const auto& [name, value] : rootColors) {
984 if (normalized.compare(0, name.size(), name) != 0) {
985 continue;
986 }
987 const auto increment = std::string_view(normalized).substr(name.size());
988 if (increment.empty()) {
989 return value;
990 }
991 if (increment.size() < 2 || (increment.front() != '+' && increment.front() != '-')) {
992 return std::nullopt;
993 }
994 int offset = 0;
995 const auto* begin = increment.data() + 1;
996 const auto* end = increment.data() + increment.size();
997 auto [parsedEnd, error] = std::from_chars(begin, end, offset);
998 if (error != std::errc{} || parsedEnd != end) {
999 return std::nullopt;
1000 }
1001 const auto signedOffset = increment.front() == '-' ? -static_cast<long long>(offset) : static_cast<long long>(offset);
1002 const auto color = static_cast<long long>(value) + signedOffset;
1003 if (color < std::numeric_limits<int>::min() || color > std::numeric_limits<int>::max()) {
1004 return std::nullopt;
1005 }
1006 return static_cast<int>(color);
1007 }
1008 return std::nullopt;
1009 };
1010 std::vector<int> colors;
1011 if (useColors) {
1012 for (const auto& colorName : colorNames) {
1013 auto color = parseColor(colorName);
1014 if (!color) {
1015 LOGP(warn, "Unrecognized EColor name '{}', will use automatic colors", colorName);
1016 useColors = false;
1017 break;
1018 }
1019 colors.push_back(*color);
1020 }
1021 }
1022 std::vector<int> markers;
1023 if (useMarkers) {
1024 for (const auto& markerID : markerIDs) {
1025 int marker = 0;
1026 const auto* begin = markerID.data();
1027 const auto* end = begin + markerID.size();
1028 auto [parsedEnd, error] = std::from_chars(begin, end, marker);
1029 if (error != std::errc{} || parsedEnd != end) {
1030 LOGP(warn, "Unrecognized marker ID '{}', will use automatic markers", markerID);
1031 useMarkers = false;
1032 break;
1033 }
1034 markers.push_back(marker);
1035 }
1036 }
1037 std::unique_ptr<TLegend> lg;
1038 lg = std::make_unique<TLegend>(0.12, 0.13, 0.9, 0.13 + std::min(0.5f, nhm * 0.2f / 3.f));
1039 lg->SetFillStyle(0);
1040 lg->SetBorderSize(0);
1041 for (int i = 0; i < nhm; i++) {
1042 auto hman = mHManV[i].get();
1043 if (!hman || hman->GetLast() < 1) {
1044 continue;
1045 }
1046 const int marker = useMarkers ? markers[i] : 20 + i + (i % 2) * 4;
1047 const int color = useColors ? colors[i] : hcol[i % hcol.size()];
1048 hman->setMarkerStyle(marker, 0.5);
1049 hman->setColor(color);
1050 auto le = lg->AddEntry(hman->getHisto(1), hman->GetName(), "lp");
1051 le->SetTextColor(color);
1052 }
1053 TCanvas cly("cly", "", 600, 800), clz("clz", "", 600, 800), clpar("clpar", "", 600, 800);
1054 TCanvas czly("czly", "", 600, 800), czlz("czlz", "", 600, 800), czlpar("czlpar", "", 600, 800);
1055 TCanvas cchip("cchip", "", 600, 800);
1056 constexpr std::array<const char*, 4> chipTitles{"#DeltaY", "pull #DeltaY", "#DeltaZ", "pull #DeltaZ"};
1057 auto AddLabel = [](const char* txt, float x = 0.1, float y = 0.9, int color = kBlack, float size = 0.04) {
1058 TLatex* lt = new TLatex(x, y, txt);
1059 lt->SetNDC();
1060 lt->SetTextColor(color);
1061 lt->SetTextSize(size);
1062 lt->Draw();
1063 return lt;
1064 };
1065
1066 auto drawResLr = [this](TCanvas& canv, int offs, const float resMM[8], bool logX) {
1067 canv.Clear();
1068 canv.Divide(2, 4);
1069 int nh = this->mHManV.size();
1070 for (int i = 0; i < 8; i++) {
1071 canv.cd(i + 1);
1072 bool same = false;
1073 for (int j = 0; j < nh; j++) {
1074 auto hman = this->mHManV[j].get();
1075 if (!hman || hman->GetLast() < 1) {
1076 continue;
1077 }
1078 if (auto histo = hman->getHisto(10 * i + offs)) {
1079 histo->Draw(same ? "same" : "");
1080 if (!same) {
1081 histo->SetMinimum(-resMM[i]);
1082 histo->SetMaximum(resMM[i]);
1083 same = true;
1084 }
1085 }
1086 }
1087 gPad->SetGrid();
1088 gPad->SetLogx(logX);
1089 }
1090 };
1091
1092 auto drawResPar = [this](TCanvas& canv, int offs, const float resMM[8], bool logX) {
1093 canv.Clear();
1094 canv.Divide(2, 3);
1095 int nh = this->mHManV.size();
1096 for (int i = 0; i < 5; i++) {
1097 canv.cd(i + 1);
1098 bool same = false;
1099 for (int j = 0; j < nh; j++) {
1100 auto hman = this->mHManV[j].get();
1101 if (!hman || hman->GetLast() < 1) {
1102 continue;
1103 }
1104 if (auto histo = hman->getHisto(10 * i + offs)) {
1105 histo->Draw(same ? "same" : "");
1106 if (!same) {
1107 histo->SetMinimum(-resMM[i]);
1108 histo->SetMaximum(resMM[i]);
1109 same = true;
1110 }
1111 }
1112 }
1113 gPad->SetGrid();
1114 gPad->SetLogx(logX);
1115 }
1116 };
1117
1118 // draws the 8 dy/dz-vs-phi/Z/pT/tgl pages (standard idOffset=0, or IOB idOffset=100000) into pdfName
1119 auto drawLrResidPages = [&](const std::string& pdfName, int idOffset) {
1120 const float dyzScale = idOffset ? params.IOBScaleFactor : 1.f; // IOB residuals have a much larger range than the standard ones
1121 std::array<float, 8> resMMY, resMMZ;
1122 for (int i = 0; i < 8; i++) {
1123 resMMY[i] = params.resMMLrY[i] * dyzScale;
1124 resMMZ[i] = params.resMMLrZ[i] * dyzScale;
1125 }
1126 drawResLr(cly, idOffset + 1, resMMY.data(), false);
1127 cly.cd(2);
1128 lg->Draw();
1129 AddLabel("Y residuals", 0.1, 0.95);
1130 cly.Print(pdfName.c_str());
1131
1132 drawResLr(clz, idOffset + 101, resMMZ.data(), false);
1133 clz.cd(2);
1134 lg->Draw();
1135 AddLabel("Z residuals", 0.1, 0.95);
1136 clz.Print(pdfName.c_str());
1137
1138 drawResLr(czly, idOffset + 1001, resMMY.data(), false);
1139 czly.cd(2);
1140 lg->Draw();
1141 AddLabel("Y residuals", 0.1, 0.95);
1142 czly.Print(pdfName.c_str());
1143
1144 drawResLr(czlz, idOffset + 1101, resMMZ.data(), false);
1145 czlz.cd(2);
1146 lg->Draw();
1147 AddLabel("Z residuals", 0.1, 0.95);
1148 czlz.Print(pdfName.c_str());
1149
1150 drawResLr(czly, idOffset + 2001, resMMY.data(), true);
1151 czly.cd(2);
1152 lg->Draw();
1153 AddLabel("Y residuals", 0.1, 0.95);
1154 czly.Print(pdfName.c_str());
1155
1156 drawResLr(czlz, idOffset + 2101, resMMZ.data(), true);
1157 czlz.cd(2);
1158 lg->Draw();
1159 AddLabel("Z residuals", 0.1, 0.95);
1160 czlz.Print(pdfName.c_str());
1161
1162 drawResLr(czly, idOffset + 3001, resMMY.data(), false);
1163 czly.cd(2);
1164 lg->Draw();
1165 AddLabel("Y residuals", 0.1, 0.95);
1166 czly.Print(pdfName.c_str());
1167
1168 drawResLr(czlz, idOffset + 3101, resMMZ.data(), false);
1169 czlz.cd(2);
1170 lg->Draw();
1171 AddLabel("Z residuals", 0.1, 0.95);
1172 czlz.Print(pdfName.c_str());
1173 };
1174
1175 const std::string mainPdf = fmt::format("{}_hman.pdf", params.outname);
1176 cly.Print(Form("%s[", mainPdf.c_str()));
1177 drawLrResidPages(mainPdf, 0);
1178
1179 drawResPar(clpar, 10001, params.resMMPar, false);
1180 clpar.cd(6);
1181 lg->Draw();
1182 AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8);
1183 clpar.Print(mainPdf.c_str());
1184
1185 drawResPar(czlpar, 11001, params.resMMPar, false);
1186 czlpar.cd(6);
1187 lg->Draw();
1188 AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8);
1189 czlpar.Print(mainPdf.c_str());
1190
1191 drawResPar(czlpar, 12001, params.resMMPar, true);
1192 czlpar.cd(6);
1193 lg->Draw();
1194 AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8);
1195 czlpar.Print(mainPdf.c_str());
1196
1197 drawResPar(czlpar, 13001, params.resMMPar, false);
1198 czlpar.cd(6);
1199 lg->Draw();
1200 AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8);
1201 czlpar.Print(mainPdf.c_str());
1202
1203 auto getHMinMax = [this](int id, float marginFrac, float maxDev, int roundToMicrons) -> std::tuple<float, float, float> {
1204 float maxV = std::numeric_limits<float>::lowest(), minV = std::numeric_limits<float>::max();
1205 const int nh = this->mHManV.size();
1206 for (int j = 0; j < nh; j++) {
1207 if (!this->mHManV[j]) {
1208 continue;
1209 }
1210 if (auto histo = this->mHManV[j]->getHisto(id); histo != nullptr) {
1211 const int nb = histo->GetNbinsX();
1212 for (int ib = 1; ib <= nb; ib++) {
1213 float v = histo->GetBinContent(ib);
1214 maxV = std::max(maxV, v);
1215 minV = std::min(minV, v);
1216 }
1217 }
1218 }
1219 if (maxV < minV) {
1220 return {0.f, 1.f, 0.1f};
1221 }
1222 auto delta = maxV - minV;
1223 maxV += delta * marginFrac;
1224 minV -= delta * marginFrac;
1225 if (roundToMicrons > 0) {
1226 maxV = ((int(std::ceil(maxV * 1e4)) / roundToMicrons + 1) * roundToMicrons) * 1e-4;
1227 minV = ((int(std::floor(minV * 1e4)) / roundToMicrons - 1) * roundToMicrons) * 1e-4;
1228 }
1229 minV = std::max(minV, -maxDev);
1230 maxV = std::min(maxV, maxDev);
1231 return {minV, maxV, std::max(std::abs(minV), std::abs(maxV))};
1232 };
1233 auto collectSpread = [](TH1* hin, TH1* hout) {
1234 const int nb = hin->GetNbinsX();
1235 for (int ib = 1; ib <= nb; ib++) {
1236 if (hin->GetBinError(ib) != 0) {
1237 hout->Fill(hin->GetBinContent(ib));
1238 }
1239 }
1240 hout->SetLineColor(hin->GetLineColor());
1241 hout->SetMarkerColor(hin->GetMarkerColor());
1242 hout->SetMarkerStyle(hin->GetMarkerStyle());
1243 };
1244 int nh = this->mHManV.size();
1245 // Draw per-chip residual/pull means and sigmas, and their half-barrel and full-layer spreads.
1246 auto drawChipPages = [&](const std::string& pdfName, int idOffset) {
1247 for (int il = 1; il < 8; ++il) {
1248 for (int iht = 0; iht < 2; iht++) { // residual or pull
1249 for (int ib = 0; ib < 3; ib++) { // two half-barrels, then the full layer
1250 if (iht == 1 && ib < 2) {
1251 continue; // Draw pulls only for the full layer.
1252 }
1253 for (int iyz = 0; iyz < 2; iyz++) {
1254 cchip.Clear();
1255 cchip.Divide(1, ib == 2 ? 2 : 4);
1256 bool havePage = false;
1257 for (int iv = 0; iv < 2; iv++) { // mean or sigma
1258 const float yRange = (iyz == 0 ? params.resMMLrY[il] : params.resMMLrZ[il]) * (idOffset ? params.IOBScaleFactor : 1.f);
1259 const int baseID = idOffset + 15000 + iyz * 10 + 2 * il * 100 + iht * 5 + 1 + iv;
1260 // Use common spread axes for both half-barrels and their full-layer sum.
1261 auto [minV, maxV, absMax] = getHMinMax(baseID, 0.15, (iv == 0 ? 2 : 8) * yRange, 10);
1262 auto [minV1, maxV1, absMax1] = getHMinMax(baseID + 100, 0.15, (iv == 0 ? 2 : 8) * yRange, 10);
1263 minV = std::min(minV, minV1);
1264 maxV = std::max(maxV, maxV1);
1265 absMax = std::max(absMax, absMax1);
1266 if (iht == 1) {
1267 minV = iv ? 0.f : -params.maxPull;
1268 maxV = absMax = params.maxPull;
1269 }
1270 bool drawn = false;
1271 TH1* firstAuto = nullptr;
1272 float maxAuto = 0.f;
1273 for (int j = 0; j < nh; j++) {
1274 auto hman = this->mHManV[j].get();
1275 if (!hman) {
1276 continue;
1277 }
1278 TH1* hmeans = nullptr;
1279 for (int hb = ib == 2 ? 0 : ib; hb < (ib == 2 ? 2 : ib + 1); hb++) {
1280 const int id = baseID + hb * 100;
1281 auto histo = hman->getHisto(id);
1282 if (!histo) {
1283 continue;
1284 }
1285 if (!hmeans) {
1286 if (ib == 2) {
1287 hmeans = new TH1F(Form("%s_layer_spread", histo->GetName()), Form("Lr%d %s %s spread", il - 1, chipTitles[2 * iyz + iht], iv ? "sigma" : "mean"), params.nBinsRes, iv == 0 ? minV : std::max(0.f, minV), maxV);
1288 hman->addHisto(hmeans, idOffset + 25000 + il * 100 + iyz * 10 + iht * 5 + iv);
1289 } else {
1290 hmeans = new TH1F(Form("%s_spread", histo->GetName()), Form("%s spread;#<Delta>", histo->GetTitle()), params.nBinsRes, iv == 0 ? minV : std::max(0.f, minV), maxV);
1291 hman->addHisto(hmeans, id + 2);
1292 }
1293 }
1294 if (iht == 0) {
1295 hmeans->SetXTitle(iv ? "<#sigma>, cm" : "<#Delta>, cm");
1296 }
1297 collectSpread(histo, hmeans);
1298 if (ib < 2) {
1299 histo->SetMaximum(absMax);
1300 histo->SetMinimum(iv ? 0 : -absMax);
1301 if (il > 3) {
1302 histo->SetMarkerSize(0.3);
1303 histo->SetLineStyle(3);
1304 }
1305 cchip.cd(2 * iv + 1);
1306 histo->Draw(drawn ? "same" : "");
1307 gPad->SetGrid();
1308 }
1309 }
1310 if (!hmeans) {
1311 continue;
1312 }
1313 cchip.cd(ib == 2 ? iv + 1 : 2 * iv + 2);
1314 if (!drawn) {
1315 firstAuto = hmeans;
1316 }
1317 maxAuto = std::max(maxAuto, (float)hmeans->GetMaximum());
1318 hmeans->Draw(drawn ? "same" : "");
1319 drawn = havePage = true;
1320 }
1321 if (firstAuto) {
1322 firstAuto->SetMaximum(maxAuto * 1.25);
1323 gPad->SetGrid();
1324 gPad->Modified();
1325 }
1326 }
1327 if (havePage) {
1328 cchip.Print(pdfName.c_str());
1329 }
1330 }
1331 }
1332 }
1333 }
1334 };
1335 drawChipPages(mainPdf, 0);
1336 cly.Print(Form("%s]", mainPdf.c_str()));
1337
1338 // IOB residuals (dyIOB/dzIOB) are optional: only produce the extra PDF if at least one loaded HistoManager actually has them booked
1339 bool haveIOB = false;
1340 for (const auto& hm : mHManV) {
1341 if (hm && hm->getHisto2F(100000 + 1 * 10)) {
1342 haveIOB = true;
1343 break;
1344 }
1345 }
1346 if (haveIOB) {
1347 const std::string iobPdf = fmt::format("{}_iob_hman.pdf", params.outname);
1348 cly.Print(Form("%s[", iobPdf.c_str()));
1349 drawLrResidPages(iobPdf, 100000);
1350 drawChipPages(iobPdf, 100000);
1351 cly.Print(Form("%s]", iobPdf.c_str()));
1352 }
1353}
1354
1356{
1357 mDBGOut.reset();
1358 if (mHManV.size()) {
1359 postProcessHistos();
1360 }
1361 if (mDraw) {
1362 drawHistos();
1363 }
1364 if (auto nh = mHManV.size(); nh > 0 && !mPostProcOnly) {
1365 for (int ihm = 0; ihm < nh; ihm++) {
1366 if (mHManV[ihm]) {
1367 mHManV[ihm].get()->write();
1368 }
1369 }
1370 }
1371}
1372
1374{
1375 if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) {
1376 return;
1377 }
1378 if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) {
1379 LOG(info) << "Imposing new MeanVertex: " << ((const o2::dataformats::MeanVertexObject*)obj)->asString();
1380 mMeanVtx = *(const o2::dataformats::MeanVertexObject*)obj;
1381 mMeanVertexUpdated = true;
1382 return;
1383 }
1384 if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) {
1385 LOG(info) << "cluster dictionary updated";
1386 mITSDict = (const o2::itsmft::TopologyDictionary*)obj;
1387 return;
1388 }
1389}
1390
1391DataProcessorSpec getCheckResidSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool drawOnly, bool postProcOnly, bool itsStag)
1392{
1393 std::vector<OutputSpec> outputs;
1394 auto dataRequest = std::make_shared<DataRequest>();
1395 dataRequest->setITSPerLayer(itsStag);
1396 if (!drawOnly && !postProcOnly) {
1397 bool useMC = false;
1398 dataRequest->requestTracks(srcTracks, useMC);
1399 dataRequest->requestClusters(srcClusters, useMC);
1400 dataRequest->requestPrimaryVertices(useMC);
1401 dataRequest->inputs.emplace_back("meanvtx", "GLO", "MEANVERTEX", 0, Lifetime::Condition, ccdbParamSpec("GLO/Calib/MeanVertex", {}, 1));
1402 }
1403 auto ggRequest = drawOnly ? std::make_shared<o2::base::GRPGeomRequest>(false, false, false, false, false, o2::base::GRPGeomRequest::None, dataRequest->inputs) : std::make_shared<o2::base::GRPGeomRequest>(false, // orbitResetTime
1404 true, // GRPECS=true
1405 true, // GRPLHCIF
1406 true, // GRPMagField
1407 true, // askMatLUT
1409 dataRequest->inputs, true);
1410 Options opts;
1411 if (!drawOnly) {
1412 opts = Options{
1413 {"nthreads", VariantType::Int, 1, {"number of threads"}},
1414 {"no-tree", VariantType::Bool, false, {"do not fill residuals tree"}},
1415 {"no-hist", VariantType::Bool, false, {"do not fill residuals histograms"}},
1416 {"draw-report", VariantType::Bool, false, {"fill residuals report"}},
1417 };
1418 }
1419
1420 return DataProcessorSpec{
1421 "check-resid",
1422 dataRequest->inputs,
1423 outputs,
1424 AlgorithmSpec{adaptFromTask<CheckResidSpec>(dataRequest, ggRequest, srcTracks, drawOnly, postProcOnly)},
1425 opts};
1426}
1427
1428} // namespace o2::checkresid
Container of the ITS/MFT clusters addressed by the composed (layer,index) ID.
Wrapper container for different reconstructed object types.
Base track model for the Barrel, params only, w/o covariance.
Definition of the GeometryManager class.
std::ostringstream debug
int32_t i
Helper for geometry and GRP related CCDB requests.
Global index for barrel track: provides provenance (detectors combination), index in respective array...
Definition of the GeometryTGeo class.
std::vector< o2::its::TrackITS > tracks
Utility functions for MC particles.
Definition of the Names Generator class.
Primary vertex finder.
uint32_t j
Definition RawData.h:0
uint16_t pid
Definition RawData.h:2
uint32_t res
Definition RawData.h:0
Wrapper container for different reconstructed object types.
o2::track::TrackParCov TrackParCov
Definition Recon.h:39
Result of refitting TPC-ITS matched track.
Reference on ITS/MFT clusters set.
Referenc on track indices contributing to the vertex, with possibility chose tracks from specific sou...
void setSigmaZ2(T v)
void setSigmaY2(T v)
void setSensorID(std::int16_t sid)
Definition BaseCluster.h:92
void setXYZ(T x, T y, T z)
int addHisto(TH1 *histo, int at=-1)
TH2F * getHisto2F(int id) const
TH1 * getHisto(int id) const
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:180
void endOfStream(EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
void run(ProcessingContext &pc) final
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj) final
CheckResidSpec(std::shared_ptr< DataRequest > dr, std::shared_ptr< o2::base::GRPGeomRequest > gr, GTrackID::mask_t src, bool drawOnly, bool postProcOnly)
void init(InitContext &ic) final
static void updateFromString(std::string const &)
Static class with identifiers, bitmasks and names for ALICE detectors.
Definition DetID.h:60
ServiceRegistryRef services()
Definition InitContext.h:34
ConfigParamRegistry const & options()
Definition InitContext.h:33
decltype(auto) get(R binding, int part=0) const
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
static GeometryTGeo * Instance()
int getClusterEntry(int i) const
Definition TrackITS.h:72
static constexpr int getNChipsOnLayer(int lr)
static constexpr int getFirstChipsOnLayer(int lr)
int getNPixels() const
Returns the number of fired pixels.
void beginLayer(int lr)
to be called once all the layers were filled
void init(int nLr)
< prepare for filling nLr layer slots, discarding the previous content
static constexpr unsigned short InvalidPatternID
Definition CompCluster.h:46
int getNpixels(int n) const
Returns the number of fired pixels of the n_th element.
bool isGroup(int n) const
Returns true if the element corresponds to a group of rare topologies.
PVertex refitVertexFull(const std::vector< bool > useTrack, const o2d::VertexBase &vtxSeed)
bool prepareVertexRefit(const TR &tracks, const o2d::VertexBase &vtxSeed)
Definition PVertexer.h:362
void setMeanVertex(const o2d::MeanVertexObject *v)
Definition PVertexer.h:98
GLfloat GLfloat GLfloat alpha
Definition glcorearb.h:279
GLint GLenum GLint x
Definition glcorearb.h:403
GLenum src
Definition glcorearb.h:1767
GLsizeiptr size
Definition glcorearb.h:659
GLuint color
Definition glcorearb.h:1272
GLuint GLuint end
Definition glcorearb.h:469
const GLdouble * v
Definition glcorearb.h:832
GLuint const GLchar * name
Definition glcorearb.h:781
GLdouble f
Definition glcorearb.h:310
GLint y
Definition glcorearb.h:270
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLenum const GLfloat * params
Definition glcorearb.h:272
GLintptr offset
Definition glcorearb.h:660
GLint GLenum GLboolean normalized
Definition glcorearb.h:867
GLint GLint GLsizei GLint GLenum format
Definition glcorearb.h:275
GLuint id
Definition glcorearb.h:650
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
uint8_t int statusCode int
o2::framework::DataProcessorSpec getCheckResidSpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool drawOnly, bool postProcOnly, bool itsStag)
create a processor spec
o2::dataformats::GlobalTrackID GTrackID
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)
std::vector< ConfigParamSpec > Options
constexpr int MaxITSLayers
constexpr unsigned int nChips
Definition SpecsV2.h:180
void convertCompactClusters(gsl::span< const itsmft::CompClusterExt > clusters, gsl::span< const unsigned char >::iterator &pattIt, std::vector< o2::BaseCluster< float > > &output, const itsmft::TopologyDictionary *dict)
convert compact clusters to 3D spacepoints
Definition IOUtils.cxx:35
o2::track::TrackParCov int int int float int nCl
return true
const bool const int TrackITSInternal< NLayers > & track
const float const float const float bz
double * getX(double *xyDxy, int N)
double * getY(double *xyDxy, int N)
Enum< T >::Iterator begin(Enum< T >)
Definition Defs.h:158
TrackParCovF TrackParCov
Definition Track.h:33
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
void empty(int)
o2::track::TrackPar track
o2::track::TrackParCov trIBOut
o2::track::TrackParCov trOBInw
std::vector< Point > points
GTrackID getITSContributorGID(GTrackID source) const
auto getITSClustersPatterns(int layer=0) const
const o2::track::TrackParCov & getTrackParam(GTrackID gidx) const
void collectData(o2::framework::ProcessingContext &pc, const DataRequest &request)
const o2::its::TrackITS & getITSTrack(GTrackID gid) const
auto getITSClusters(int layer=0) const
static std::vector< std::string > tokenize(const std::string &src, char delim, bool trimToken=true, bool skipEmpty=true)
constexpr size_t max
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
Cluster clu