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 <vector>
17#include <TStopwatch.h>
36#include "ITStracking/IOUtils.h"
44#include <TROOT.h>
45#include <TStyle.h>
46#include <TLatex.h>
47#include <TCanvas.h>
48#include <TLegend.h>
49#include <TLegendEntry.h>
50#include <TH1F.h>
51#include <TH2F.h>
52#include <TProfile.h>
53#include <TGraph.h>
54#include <TF1.h>
55#ifdef WITH_OPENMP
56#include <omp.h>
57#endif
58
59// Attention: in case the residuals are checked with geometry different from the one used for initial reconstruction,
60// pass a --configKeyValues option for vertex refit as:
61// ;pvertexer.useMeanVertexConstraint=false;pvertexer.meanVertexExtraErrSelection=0.2;pvertexer.iniScale2=100;pvertexer.acceptableScale2=10.;
62// In any case, it is better to pass ;pvertexer.useMeanVertexConstraint=false;
63
64namespace o2::checkresid
65{
66using namespace o2::framework;
69
76
77class CheckResidSpec final : public Task
78{
79 public:
80 CheckResidSpec(std::shared_ptr<DataRequest> dr, std::shared_ptr<o2::base::GRPGeomRequest> gr, GTrackID::mask_t src, bool drawOnly, bool postProcOnly)
81 : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mDrawOnly(drawOnly), mPostProcOnly(postProcOnly)
82 {
83 }
84 ~CheckResidSpec() final = default;
85 void init(InitContext& ic) final;
86 void run(ProcessingContext& pc) final;
87 void endOfStream(EndOfStreamContext& ec) final;
88 void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final;
89 void process();
90
91 private:
92 void updateTimeDependentParams(ProcessingContext& pc);
93 bool refitPV(o2::dataformats::PrimaryVertex& pv, int vid);
94 bool refitITStrack(o2::track::TrackParCov& track, GTrackID gid);
95 bool processITSTrack(const o2::its::TrackITS& iTrack, const o2::dataformats::PrimaryVertex& pv, o2::checkresid::Track& resTrack, o2::track::PID pid);
96 void bookHistos();
97 void fillHistos(const o2::checkresid::Track& trc);
98 void postProcessHistos();
99 void drawHistos();
100
101 o2::globaltracking::RecoContainer* mRecoData = nullptr;
102 int mNThreads = 1;
103 bool mMeanVertexUpdated = false;
104 float mITSROFrameLengthMUS = 0.f;
105 o2::dataformats::MeanVertexObject mMeanVtx{};
106 ITSClusters mITSClustersArray;
107 const o2::itsmft::TopologyDictionary* mITSDict = nullptr;
108 o2::vertexing::PVertexer mVertexer;
109 std::shared_ptr<DataRequest> mDataRequest;
110 std::shared_ptr<o2::base::GRPGeomRequest> mGGCCDBRequest;
111 std::unique_ptr<o2::utils::TreeStreamRedirector> mDBGOut;
112 GTrackID::mask_t mTracksSrc{};
113
114 bool mDrawOnly = false;
115 bool mPostProcOnly = false;
116 bool mDraw = false;
117 bool mFillHistos = true;
118 bool mFillTree = true;
119 std::vector<std::unique_ptr<o2::HistoManager>> mHManV{};
120 std::vector<o2::dataformats::PrimaryVertex> mPVUsed;
121 o2::HistoManager* mHMan = nullptr;
122};
123
125{
126 mDraw = true;
127 if (!mDrawOnly) {
128 mDraw = ic.options().get<bool>("draw-report");
129 mFillHistos = !ic.options().get<bool>("no-hist");
130 mFillTree = !ic.options().get<bool>("no-tree");
131 mNThreads = ic.options().get<int>("nthreads");
132 }
134 int lane = ic.services().get<const o2::framework::DeviceSpec>().inputTimesliceId;
135 int maxLanes = ic.services().get<const o2::framework::DeviceSpec>().maxInputTimeslices;
136 std::string nm = params.outname;
137 if (maxLanes > 1) {
138 o2::conf::ConfigurableParam::updateFromString(fmt::format("checkresid.outname={}_t{}", nm, lane));
139 }
140 if (mDraw) {
141 mFillHistos = true;
142 }
143 if (!mDrawOnly && mFillHistos) {
144 bookHistos();
145 }
146 if (!params.ext_hm_list.empty()) {
147 auto vecNames = o2::utils::Str::tokenize(params.ext_hm_list, ',');
148 auto vecLegends = o2::utils::Str::tokenize(params.ext_leg_list, ',');
149 bool useLeg = true;
150 if (vecNames.size() != vecLegends.size()) {
151 LOGP(warn, "{} legend names provided for {} external histomanagers, will use file names as legends", vecLegends.size(), vecNames.size());
152 useLeg = false;
153 }
154 int cntH = 0;
155 for (const auto& vn : vecNames) {
156 LOGP(info, "Loading external HistoManager {}", vn);
157 mHManV.emplace_back() = std::make_unique<o2::HistoManager>("", vn, true);
158 auto hm = mHManV.back().get();
159 if (!hm) {
160 LOGP(error, "Failed to load histograms from {}", vn);
161 mHManV.pop_back();
162 } else {
163 hm->SetName(useLeg ? vecLegends[cntH].c_str() : vn.c_str());
164 }
165 cntH++;
166 }
167 }
168 if (mDrawOnly) {
169 return;
170 }
172#ifndef WITH_OPENMP
173 if (mNThreads > 1) {
174 LOGP(warn, "No OpenMP");
175 }
176 mNThreads = 1;
177#endif
178 if (mFillTree) {
179 mDBGOut = std::make_unique<o2::utils::TreeStreamRedirector>(fmt::format("{}.root", params.outname).c_str(), "recreate");
180 }
181}
182
184{
185 bool quit = false;
186 if (mPostProcOnly) {
187
188 postProcessHistos();
189 quit = true;
190 }
191 if (mDrawOnly) {
192 drawHistos();
193 quit = true;
194 }
195 if (quit) {
197 pc.services().get<ControlService>().readyToQuit(QuitRequest::Me);
198 return;
199 }
201 mRecoData = &recoData;
202 mRecoData->collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer
203 mRecoData = &recoData;
204 updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions
205 process();
206 mRecoData = nullptr;
207}
208
209void CheckResidSpec::updateTimeDependentParams(ProcessingContext& pc)
210{
213 static bool initOnceDone = false;
214 if (!initOnceDone) { // this params need to be queried only once
216 initOnceDone = true;
217 // Note: reading of the ITS AlpideParam needed for ITS timing is done by the RecoContainer
220 if (!grp->isDetContinuousReadOut(DetID::ITS)) {
221 mITSROFrameLengthMUS = alpParams.roFrameLengthTrig / 1.e3; // ITS ROFrame duration in \mus
222 } else {
223 mITSROFrameLengthMUS = alpParams.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS * 1e-3; // ITS ROFrame duration in \mus
224 }
226 geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G, o2::math_utils::TransformType::T2G));
227 o2::conf::ConfigurableParam::updateFromString("pvertexer.useTimeInChi2=false;");
228 mVertexer.init();
229 }
230 if (mMeanVertexUpdated) {
231 mMeanVertexUpdated = false;
232 mVertexer.setMeanVertex(&mMeanVtx);
233 mVertexer.initMeanVertexConstraint();
234 }
235}
236
238{
239 if (!mITSDict) {
240 LOGP(fatal, "ITS data is not loaded");
241 }
242 const auto itsTracks = mRecoData->getITSTracks();
243 // const auto itsLbls = mRecoData->getITSTracksMCLabels();
244 const auto itsClRefs = mRecoData->getITSTracksClusterRefs();
246 int nLr = mDataRequest->getITSPerLayer() ? o2::globaltracking::MaxITSLayers : 1;
247 mITSClustersArray.init(nLr);
248 for (int lr = 0; lr < nLr; lr++) { // with a single (monolithic) input all clusters are in the layer slot 0
249 mITSClustersArray.beginLayer(lr);
250 const auto clusITS = mRecoData->getITSClusters(lr);
251 auto pattIt = mRecoData->getITSClustersPatterns(lr).begin();
252 mITSClustersArray.getClusters().reserve(mITSClustersArray.size() + clusITS.size());
253 o2::its::ioutils::convertCompactClusters(clusITS, pattIt, mITSClustersArray.getClusters(), mITSDict);
254 }
255 mITSClustersArray.finalize();
256
257 auto pvvec = mRecoData->getPrimaryVertices();
258 auto trackIndex = mRecoData->getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks
259 auto vtxRefs = mRecoData->getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs
260 auto prop = o2::base::Propagator::Instance();
261 static int TFCount = 0;
262 int nv = vtxRefs.size() - 1;
263 std::vector<std::vector<checkresid::Track>> slots;
264 mPVUsed.clear();
265 slots.resize(mNThreads);
266 int nvGood = 0, nvUse = 0, nvRefFail = 0;
267 long pvFitDuration{};
268 for (int iv = 0; iv < nv; iv++) {
269 const auto& vtref = vtxRefs[iv];
270 auto pve = pvvec[iv];
271 if (pve.getNContributors() < params.minPVContributors) {
272 continue;
273 }
274 nvGood++;
275 if (params.refitPV) {
276 LOGP(debug, "Refitting PV#{} of {} tracks", iv, pve.getNContributors());
277 auto tStartPVF = std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
278 bool res = refitPV(pve, iv);
279 pvFitDuration += std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count() - tStartPVF;
280 if (!res) {
281 nvRefFail++;
282 continue;
283 }
284 }
285 nvUse++;
286 mPVUsed.push_back(pve);
287 const auto& itsContRefs = vtref.getITSGloContributors();
288 int idMinITSGlo = 0, idMaxITSGlo = 0;
289 if (params.useITSGloContributors) {
290 if (itsContRefs.getFirstEntry() < vtref.getEntries() && itsContRefs.getEntries() == 0) {
291 LOGP(fatal, "Usage of stored ITS global contributors is requested but they are missing");
292 }
293 idMinITSGlo = itsContRefs.getFirstEntry();
294 idMaxITSGlo = idMinITSGlo + itsContRefs.getEntries();
295 }
296 int cntPVCont = 0;
297 for (int is = 0; is < GTrackID::NSources; is++) {
298 if (!params.useITSGloContributors && (!mTracksSrc[is] || !mRecoData->isTrackSourceLoaded(is))) {
299 continue;
300 }
301 int idMin = vtref.getFirstEntryOfSource(is), idMax = idMin + vtref.getEntriesOfSource(is);
302 DetID::mask_t dm = GTrackID::getSourceDetectorsMask(is);
303 if (!dm[DetID::ITS]) {
304 continue;
305 }
306#ifdef WITH_OPENMP
307#pragma omp parallel for schedule(dynamic) num_threads(mNThreads)
308#endif
309 for (int i = idMin; i < idMax; i++) {
310 auto vid = trackIndex[i];
311 bool pvCont = vid.isPVContributor();
312 if (!pvCont && (params.pvcontribOnly || params.useITSGloContributors)) {
313 continue;
314 }
315 GTrackID gidITS;
316 o2::track::PID pidITS;
317 if (params.useITSGloContributors) {
318 int id = idMinITSGlo + cntPVCont;
319 if (id >= idMaxITSGlo) {
320 LOGP(fatal, "Calculated GlobalContributor ITS track index {} exceeds number of stored indices {}", id, itsContRefs.getEntries());
321 }
322 pidITS = trackIndex[id].getSource();
323 gidITS = GTrackID(trackIndex[id].getIndex(), GTrackID::ITS);
324 cntPVCont++;
325 } else {
326 gidITS = mRecoData->getITSContributorGID(vid);
327 if (gidITS.getSource() != GTrackID::ITS) {
328 continue;
329 }
330 }
331 const auto& itsTrack = mRecoData->getITSTrack(gidITS);
332 if (itsTrack.getNClusters() < params.minITSCl) {
333 continue;
334 }
335 const auto& trc = params.useITSGloContributors ? ((o2::track::TrackParCov&)itsTrack) : mRecoData->getTrackParam(vid);
336 if (!params.useITSGloContributors) {
337 pidITS = trc.getPID();
338 }
339 auto pt = trc.getPt();
340 if (pt < params.minPt || pt > params.maxPt) {
341 continue;
342 }
343 if (std::abs(trc.getTgl()) > params.maxTgl) {
344 continue;
345 }
346#ifdef WITH_OPENMP
347 auto& accum = slots[omp_get_thread_num()];
348#else
349 auto& accum = slots[0];
350#endif
351 auto& resTrack = accum.emplace_back();
352 resTrack.gid = vid;
353 if (!processITSTrack(itsTrack, pve, resTrack, pidITS)) {
354 accum.pop_back();
355 continue;
356 }
357 }
358 }
359 }
360 // output
361 for (const auto& accum : slots) {
362 for (const auto& tr : accum) {
363 if (mDBGOut) {
364 (*mDBGOut) << "res" << "tr=" << tr << "\n";
365 }
366 if (mHMan) {
367 fillHistos(tr);
368 }
369 }
370 }
371 if (mDBGOut) {
372 (*mDBGOut) << "pvUsed" << "pv=" << mPVUsed << "\n";
373 }
374 if (mHMan) {
375 for (const auto& pv : mPVUsed) {
376 mHMan->getHisto(20000 + 0)->Fill(pv.getX());
377 mHMan->getHisto(20000 + 1)->Fill(pv.getY());
378 mHMan->getHisto(20000 + 2)->Fill(pv.getZ());
379 mHMan->getHisto(20000 + 3)->Fill(pv.getNContributors());
380 }
381 }
382 LOGP(info, "processed {} PVs out of {} good vertices (out of {} in total), PV refits took {} mus, {} refits failed", nvUse, nvGood, nv, pvFitDuration, nvRefFail);
383 TFCount++;
384}
385
386bool CheckResidSpec::processITSTrack(const o2::its::TrackITS& iTrack, const o2::dataformats::PrimaryVertex& pv, o2::checkresid::Track& resTrack, o2::track::PID pid)
387{
388 const auto itsClRefs = mRecoData->getITSTracksClusterRefs();
389 auto trFitInw = iTrack.getParamOut(); // seed for inward refit
390 auto trFitOut = iTrack.getParamIn(); // seed for outward refit
391 trFitInw.setPID(pid);
392 trFitOut.setPID(pid);
393 auto prop = o2::base::Propagator::Instance();
395 float pvAlpha = 0;
396 float bz = prop->getNominalBz();
397 std::array<const o2::BaseCluster<float>*, 8> clArr{};
398 const auto& params = CheckResidConfig::Instance();
399 std::array<o2::track::TrackParCov, 8> extrapOut, extrapInw; // 2-way Kalman extrapolations, vertex + 7 layers
400
401 auto rotateTrack = [bz](o2::track::TrackParCov& tr, float alpha, o2::track::TrackPar* refLin) {
402 return refLin ? tr.rotate(alpha, *refLin, bz) : tr.rotate(alpha);
403 };
404
405 auto accountCluster = [&](int i, std::array<o2::track::TrackParCov, 8>& extrapDest, o2::track::TrackParCov& tr, o2::track::TrackPar* refLin) {
406 if (clArr[i]) { // update with cluster
407 if (!rotateTrack(tr, i == 0 ? pvAlpha : geom->getSensorRefAlpha(clArr[i]->getSensorID()), refLin) ||
408 !prop->propagateTo(tr, refLin, clArr[i]->getX(), true)) {
409 return 0;
410 }
411 extrapDest[i] = tr; // before update
412 if (!tr.update(*clArr[i])) {
413 return 0;
414 }
415 } else {
416 extrapDest[i].invalidate();
417 return -1;
418 }
419 return 1;
420 };
421
422 auto inv2d = [](float s00, float s11, float s01) -> std::array<float, 3> {
423 auto det = s00 * s11 - s01 * s01;
424 if (det < 1e-16) {
425 LOGP(error, "Singular det {}, input: {} {} {}", det, s00, s11, s01);
426 return {0.f, 0.f, 0.f};
427 }
428 det = 1.f / det;
429 return {s11 * det, s00 * det, -s01 * det};
430 };
431
432 resTrack.points.clear();
433 if (!prop->propagateToDCA(pv, trFitOut, bz)) {
434 LOGP(debug, "Failed to propagateToDCA, {}", trFitOut.asString());
435 return false;
436 }
438 if (params.addPVAsCluster) {
439 float cosAlp, sinAlp;
440 pvAlpha = trFitOut.getAlpha();
441 o2::math_utils::sincos(trFitOut.getAlpha(), sinAlp, cosAlp); // vertex position rotated to track frame
442 bcPV.setXYZ(pv.getX() * cosAlp + pv.getY() * sinAlp, -pv.getX() * sinAlp + pv.getY() * cosAlp, pv.getZ());
443 bcPV.setSigmaY2(0.5 * (pv.getSigmaX2() + pv.getSigmaY2()));
444 bcPV.setSigmaZ2(pv.getSigmaZ2());
445 bcPV.setSensorID(-1);
446 clArr[0] = &bcPV;
447 }
448 // collect all track clusters to array, placing them to layer+1 slot
449 int nCl = iTrack.getNClusters();
450 for (int i = 0; i < nCl; i++) { // clusters are ordered from the outermost to the innermost
451 const auto& curClu = mITSClustersArray[itsClRefs[iTrack.getClusterEntry(i)]];
452
453 int llr = geom->getLayer(curClu.getSensorID());
454 if (clArr[1 + llr]) {
455 LOGP(error, "Cluster at lr {} was already assigned, old sens {}, new sens {}", llr, clArr[1 + llr]->getSensorID(), curClu.getSensorID());
456 }
457 clArr[1 + geom->getLayer(curClu.getSensorID())] = &curClu;
458 }
459 o2::track::TrackPar refLinInw0, refLinOut0, *refLinOut = nullptr, *refLinInw = nullptr;
460 o2::track::TrackPar refLinIBOut0, refLinOBInw0, *refLinOBInw = nullptr, *refLinIBOut = nullptr;
461 if (params.useStableRef) {
462 refLinOut = &(refLinOut0 = trFitOut);
463 refLinInw = &(refLinInw0 = trFitInw);
464 }
465 trFitOut.resetCovariance();
466 trFitOut.setCov(trFitOut.getQ2Pt() * trFitOut.getQ2Pt() * trFitOut.getCov()[14], 14);
467 trFitInw.resetCovariance();
468 trFitInw.setCov(trFitInw.getQ2Pt() * trFitInw.getQ2Pt() * trFitInw.getCov()[14], 14);
469 // fit in inward and outward direction
470 for (int i = 0; i <= 7; i++) {
471 int resOut, resInw;
472 // process resOut in ascending order (0-->7) and resInw in descending order (7-->0)
473 if (!(resOut = accountCluster(i, extrapOut, trFitOut, refLinOut)) || !(resInw = accountCluster(7 - i, extrapInw, trFitInw, refLinInw))) {
474 return false;
475 }
476 // at layer 3, find the IB track (trIBOut) and the OB track (trOBInw)
477 // propagate both trcaks to a common radius, RCompIBOB (12cm), and rotates
478 // them to the same reference frame for comparison
479 if (i == 3 && resOut == 1 && resInw == 1 && params.doIBOB && nCl == 7) {
480 resTrack.trIBOut = trFitOut; // outward track updated at outermost IB layer
481 resTrack.trOBInw = trFitInw; // inward track updated at innermost OB layer
482 o2::track::TrackPar refLinIBOut0, refLinIBIn0;
483 if (refLinOut) {
484 refLinIBOut = &(refLinIBOut0 = refLinOut0);
485 refLinOBInw = &(refLinOBInw0 = refLinInw0);
486 }
487 float xRref;
488 if (!resTrack.trOBInw.getXatLabR(params.rCompIBOB, xRref, bz) ||
489 !prop->propagateTo(resTrack.trOBInw, refLinOBInw, xRref, true) ||
490 !rotateTrack(resTrack.trOBInw, resTrack.trOBInw.getPhiPos(), refLinOBInw) || // propagate OB track to ref R and rotate
491 !rotateTrack(resTrack.trIBOut, resTrack.trOBInw.getAlpha(), refLinIBOut) ||
492 !prop->propagateTo(resTrack.trIBOut, refLinIBOut, resTrack.trOBInw.getX(), true)) { // rotate OB track to same frame and propagate to same X
493 // if any propagation or rotation steps fail, invalidate both tracks
494 return false;
495 }
496 }
497 }
498
499 bool innerDone = false;
500 if (params.doResid) {
501 for (int i = 0; i <= 7; i++) {
502 if (clArr[i]) {
503 // calculate interpolation as a weighted mean of inward/outward extrapolations to this layer
504 const auto &tInw = extrapInw[i], &tOut = extrapOut[i];
505 auto wInw = inv2d(tInw.getSigmaY2(), tInw.getSigmaZ2(), tInw.getSigmaZY());
506 auto wOut = inv2d(tOut.getSigmaY2(), tOut.getSigmaZ2(), tOut.getSigmaZY());
507 if (wInw[0] == 0.f || wOut[0] == 0.f) {
508 return false;
509 }
510 std::array<float, 3> wTot = {wInw[0] + wOut[0], wInw[1] + wOut[1], wInw[2] + wOut[2]};
511 auto cTot = inv2d(wTot[0], wTot[1], wTot[2]);
512 auto ywi = wInw[0] * tInw.getY() + wInw[2] * tInw.getZ() + wOut[0] * tOut.getY() + wOut[2] * tOut.getZ();
513 auto zwi = wInw[2] * tInw.getY() + wInw[1] * tInw.getZ() + wOut[2] * tOut.getY() + wOut[1] * tOut.getZ();
514 auto yw = ywi * cTot[0] + zwi * cTot[2];
515 auto zw = ywi * cTot[2] + zwi * cTot[1];
516 // posCl.push_back(clArr[i]->getXYZGlo(*o2::its::GeometryTGeo::Instance()));
517 auto phi = i == 0 ? tInw.getPhi() : tInw.getPhiPos();
518 o2::math_utils::bringTo02Pi(phi);
519 resTrack.points.emplace_back(clArr[i]->getY() - yw, clArr[i]->getZ() - zw, cTot[0] + clArr[i]->getSigmaY2(), cTot[1] + clArr[i]->getSigmaZ2(), phi, clArr[i]->getZ(), clArr[i]->getSensorID(), i - 1);
520 if (!innerDone) {
521 resTrack.track = tInw;
522 innerDone = true;
523 }
524 } else {
525 LOGP(debug, "No cluster on lr {}", i);
526 }
527 }
528 }
529 return true;
530}
531
532bool CheckResidSpec::refitPV(o2::dataformats::PrimaryVertex& pv, int vid)
533{
535 std::vector<o2::track::TrackParCov> tracks;
536 std::vector<bool> useTrack;
537 std::vector<GTrackID> gidsITS;
538 int ntr = pv.getNContributors(), ntrIni = ntr;
539 tracks.reserve(ntr);
540 useTrack.reserve(ntr);
541 gidsITS.reserve(ntr);
542 const auto& vtref = mRecoData->getPrimaryVertexMatchedTrackRefs()[vid];
543 auto trackIndex = mRecoData->getPrimaryVertexMatchedTracks();
544 const auto& itsContRefs = vtref.getITSGloContributors();
545 if (params.useITSGloContributors && itsContRefs.getEntries()) {
546 int itr = itsContRefs.getFirstEntry(), itLim = itr + itsContRefs.getEntries();
547 for (; itr < itLim; itr++) {
548 auto tid = trackIndex[itr]; // these are ITS tracks, the Source part is substituted by the PID!!!
549 tracks.emplace_back().setPID(tid.getSource());
550 gidsITS.emplace_back(tid.getIndex(), GTrackID::ITS);
551 }
552 } else {
553 int itr = vtref.getFirstEntry(), itLim = itr + vtref.getEntries();
554 for (; itr < itLim; itr++) {
555 auto tid = trackIndex[itr];
556 if (tid.isPVContributor() && mRecoData->isTrackSourceLoaded(tid.getSource())) {
557 tracks.emplace_back().setPID(mRecoData->getTrackParam(tid).getPID());
558 gidsITS.push_back(mRecoData->getITSContributorGID(tid));
559 }
560 }
561 }
562 ntr = tracks.size();
563 useTrack.resize(ntr);
564#ifdef WITH_OPENMP
565#pragma omp parallel for schedule(dynamic) num_threads(mNThreads)
566#endif
567 for (int itr = 0; itr < ntr; itr++) {
568 if (!(useTrack[itr] = refitITStrack(tracks[itr], gidsITS[itr]))) {
569 tracks[itr] = mRecoData->getTrackParam(gidsITS[itr]); // this track will not be used but participates in prepareVertexRefit
570 }
571 }
572 ntr = 0;
573 for (auto v : useTrack) {
574 ntr++;
575 }
576 if (ntr < params.minPVContributors || !mVertexer.prepareVertexRefit(tracks, pv)) {
577 LOGP(warn, "Abandon vertex refit: NcontribNew = {} vs NcontribOld = {}", ntr, ntrIni);
578 return false;
579 }
580 LOGP(debug, "Original vtx: Nc:{} {}, chi2={}", pv.getNContributors(), pv.asString(), pv.getChi2());
581 auto pvSave = pv;
582 pv = mVertexer.refitVertexFull(useTrack, pv);
583 LOGP(debug, "Refitted vtx: Nc:{} {}, chi2={}", ntr, pv.asString(), pv.getChi2());
584 if (pv.getChi2() < 0.f) {
585 LOGP(warn, "Failed to refit PV {}", pvSave.asString());
586 return false;
587 }
588 return true;
589}
590
591bool CheckResidSpec::refitITStrack(o2::track::TrackParCov& track, GTrackID gid)
592{
593 // destination tack might have non-default PID assigned
594 const auto& trkITS = mRecoData->getITSTrack(gid);
595 const auto itsClRefs = mRecoData->getITSTracksClusterRefs();
596 const auto& params = CheckResidConfig::Instance();
597 auto pid = track.getPID();
598 track = trkITS.getParamOut();
599 track.resetCovariance();
600 track.setCov(track.getQ2Pt() * track.getQ2Pt() * track.getCov()[14], 14);
601 track.setPID(pid);
602 auto nCl = trkITS.getNumberOfClusters();
604 auto prop = o2::base::Propagator::Instance();
605 float bz = prop->getNominalBz();
607
608 for (int iCl = 0; iCl < nCl; iCl++) { // clusters are stored from outer to inner layers
609 const auto& cls = mITSClustersArray[itsClRefs[trkITS.getClusterEntry(iCl)]];
610 auto alpha = geom->getSensorRefAlpha(cls.getSensorID());
611 if (!(params.useStableRef ? track.rotate(alpha, refLin, bz) : track.rotate(alpha)) ||
612 !prop->propagateTo(track, params.useStableRef ? &refLin : nullptr, cls.getX(), true)) {
613 LOGP(debug, "refitITStrack failed on propagation to cl#{}, alpha={}, x={} | {}", iCl, alpha, cls.getX(), track.asString());
614 return false;
615 }
616 if (!track.update(cls)) {
617 LOGP(debug, "refitITStrack failed on update with cl#{}, | {}", iCl, track.asString());
618 return false;
619 }
620 }
621 return true;
622}
623
624void CheckResidSpec::fillHistos(const o2::checkresid::Track& trc)
625{
626 const auto& params = CheckResidConfig::Instance();
627 int np = trc.points.size();
628 auto pt = trc.track.getPt();
629 if (pt < params.minPt || pt > params.maxPt) {
630 return;
631 }
632 for (int ip = 0; ip < np; ip++) {
633 const auto& pnt = trc.points[ip];
634 int il = pnt.lr >= 0 ? pnt.lr + 1 : 0;
635 mHMan->getHisto2F(il * 10 + 0 * 100)->Fill(pnt.phi, pnt.dy);
636 mHMan->getHisto2F(il * 10 + 0 * 100 + 1000)->Fill(pnt.z, pnt.dy);
637 mHMan->getHisto2F(il * 10 + 0 * 100 + 2000)->Fill(pt, pnt.dy);
638 mHMan->getHisto2F(il * 10 + 0 * 100 + 3000)->Fill(trc.track.getTgl(), pnt.dy);
639 if (pnt.sig2y > 0) {
640 auto pull = pnt.dy / std::sqrt(pnt.sig2y);
641 mHMan->getHisto2F(il * 10 + 0 * 100 + 5)->Fill(pnt.phi, pull);
642 mHMan->getHisto2F(il * 10 + 0 * 100 + 5 + 1000)->Fill(pnt.z, pull);
643 mHMan->getHisto2F(il * 10 + 0 * 100 + 5 + 2000)->Fill(pt, pull);
644 mHMan->getHisto2F(il * 10 + 0 * 100 + 5 + 3000)->Fill(trc.track.getTgl(), pull);
645 }
646 mHMan->getHisto2F(il * 10 + 1 * 100)->Fill(pnt.phi, pnt.dz);
647 mHMan->getHisto2F(il * 10 + 1 * 100 + 1000)->Fill(pnt.z, pnt.dz);
648 mHMan->getHisto2F(il * 10 + 1 * 100 + 2000)->Fill(pt, pnt.dz);
649 mHMan->getHisto2F(il * 10 + 1 * 100 + 3000)->Fill(trc.track.getTgl(), pnt.dz);
650 if (pnt.sig2z > 0) {
651 auto pull = pnt.dz / std::sqrt(pnt.sig2z);
652 mHMan->getHisto2F(il * 10 + 1 * 100 + 5)->Fill(pnt.phi, pull);
653 mHMan->getHisto2F(il * 10 + 1 * 100 + 5 + 1000)->Fill(pnt.z, pull);
654 mHMan->getHisto2F(il * 10 + 1 * 100 + 5 + 2000)->Fill(pt, pull);
655 mHMan->getHisto2F(il * 10 + 1 * 100 + 5 + 3000)->Fill(trc.track.getTgl(), pull);
656 }
657 }
658 //--------------
659 if (trc.trIBOut.getX() > 1 && std::abs(trc.trIBOut.getX() - trc.trOBInw.getX()) < 0.1) {
660 for (int ip = 0; ip < 5; ip++) {
661 float d = trc.trIBOut.getParam(ip) - trc.trOBInw.getParam(ip);
662 mHMan->getHisto2F(10000 + ip * 10)->Fill(trc.trIBOut.getPhiPos(), d);
663 mHMan->getHisto2F(11000 + ip * 10)->Fill(trc.trIBOut.getZ(), d);
664 mHMan->getHisto2F(12000 + ip * 10)->Fill(pt, d);
665 mHMan->getHisto2F(13000 + ip * 10)->Fill(trc.track.getTgl(), d);
666 float sg = trc.trIBOut.getCovarElem(ip, ip) + trc.trOBInw.getCovarElem(ip, ip);
667 if (sg > 0) {
668 auto pull = d / std::sqrt(sg);
669 mHMan->getHisto2F(10000 + ip * 10 + 5)->Fill(trc.trIBOut.getPhiPos(), pull);
670 mHMan->getHisto2F(11000 + ip * 10 + 5)->Fill(trc.trIBOut.getZ(), pull);
671 mHMan->getHisto2F(12000 + ip * 10 + 5)->Fill(pt, pull);
672 mHMan->getHisto2F(13000 + ip * 10 + 5)->Fill(trc.track.getTgl(), pull);
673 }
674 }
675 }
676}
677
678void CheckResidSpec::bookHistos()
679{
681 mHManV.emplace_back() = std::make_unique<o2::HistoManager>("", fmt::format("{}_hman.root", params.outname));
682 mHMan = mHManV.back().get();
683 mHMan->SetName(params.outname.c_str());
684 auto defLogAxis = [](float xMn, float xMx, int nbin) { // get array for log axis
685 if (xMn <= 0 || xMx <= xMn || nbin < 2) {
686 LOGP(fatal, "Wrong log axis request: xmin = {} xmax = {} nbins = {}", xMn, xMx, nbin);
687 }
688 auto dx = std::log(xMx / xMn) / nbin;
689 std::vector<double> xax(nbin + 1);
690 for (int i = 0; i <= nbin; i++) {
691 xax[i] = xMn * std::exp(dx * i);
692 }
693 return xax;
694 };
695 float minPt = std::max(0.1f, params.minPt), maxPt = std::min(50.f, params.maxPt);
696 auto ptax = defLogAxis(minPt, maxPt, params.nBinsPt);
697
698 for (int il = 0; il < 8; il++) {
699 std::string lrName = il == 0 ? "Vtx" : fmt::format("Lr{}", il - 1);
700 for (int iyz = 0; iyz < 2; iyz++) {
701 std::string dname = iyz == 0 ? "dy" : "dz", dtit = iyz == 0 ? "#DeltaY" : "#DeltaZ";
702 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, -params.maxDYZ[il], params.maxDYZ[il]);
703 mHMan->addHisto(h2, il * 10 + iyz * 100);
704 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);
705 mHMan->addHisto(h2p, il * 10 + iyz * 100 + 5);
706
707 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, -params.maxDYZ[il], params.maxDYZ[il]);
708 mHMan->addHisto(hz2, il * 10 + iyz * 100 + 1000);
709 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);
710 mHMan->addHisto(hz2p, il * 10 + iyz * 100 + 5 + 1000);
711
712 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, -params.maxDYZ[il], params.maxDYZ[il]);
713 mHMan->addHisto(hpt2, il * 10 + iyz * 100 + 2000);
714 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);
715 mHMan->addHisto(hpt2p, il * 10 + iyz * 100 + 5 + 2000);
716
717 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, -params.maxDYZ[il], params.maxDYZ[il]);
718 mHMan->addHisto(htgl2, il * 10 + iyz * 100 + 3000);
719 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);
720 mHMan->addHisto(htgl2p, il * 10 + iyz * 100 + 5 + 3000);
721 }
722 }
723
724 for (int ip = 0; ip < 5; ip++) {
725 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]);
726 mHMan->addHisto(h2, 10000 + ip * 10);
727 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);
728 mHMan->addHisto(h2p, 10000 + ip * 10 + 5);
729
730 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]);
731 mHMan->addHisto(hz2, 11000 + ip * 10);
732 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);
733 mHMan->addHisto(hz2p, 11000 + ip * 10 + 5);
734
735 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]);
736 mHMan->addHisto(hpt2, 12000 + ip * 10);
737 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);
738 mHMan->addHisto(hpt2p, 12000 + ip * 10 + 5);
739
740 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]);
741 mHMan->addHisto(htgl2, 13000 + ip * 10);
742 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);
743 mHMan->addHisto(htgl2p, 13000 + ip * 10 + 5);
744 }
745 // used PV
746 mHMan->addHisto(new TH1F("pvX", "PV X;x;", params.nBinsPVXYZ, -params.maxHPVXY, params.maxHPVXY), 20000 + 0);
747 mHMan->addHisto(new TH1F("pvY", "PV Y;y;", params.nBinsPVXYZ, -params.maxHPVXY, params.maxHPVXY), 20000 + 1);
748 mHMan->addHisto(new TH1F("pvZ", "PV Z;z;", params.nBinsPVXYZ, -params.maxHPVZ, params.maxHPVZ), 20000 + 2);
749 mHMan->addHisto(new TH1F("pvN", "PV Contributors;Nc;", params.maxHPVN, 1.5, params.maxHPVN + 1.5), 20000 + 3);
750}
751
752void CheckResidSpec::postProcessHistos()
753{
754 printf("Fitting histos\n");
755 if (!mHMan) {
756 if (mHManV.empty()) {
757 LOGP(warn, "nothing to process");
758 return;
759 }
760 mHMan = mHManV[0].get();
761 }
763 auto gs = new TF1("gs", "gaus", -1, 1);
764 int maxH = mPostProcOnly ? mHManV.size() : 1;
765 TObjArray arr;
766 for (int ihm = 0; ihm < maxH; ihm++) {
767 auto* histm = mHManV[ihm].get();
768 auto fitSlices = [&](int id) {
769 auto h2 = histm->getHisto2F(id);
770 if (!h2 || h2->GetEntries() < params.minHistoStat2Fit) {
771 return;
772 }
773 h2->FitSlicesY(gs, 0, -1, 0, "QNR", &arr);
774 arr.SetOwner(true);
775 TH1* hmean = (TH1*)arr.RemoveAt(1);
776 if (hmean) {
777 hmean->SetTitle(Form("<%s>", h2->GetTitle()));
778 histm->addHisto(hmean, id + 1);
779 }
780 TH1* hsig = (TH1*)arr.RemoveAt(2);
781 if (hsig) {
782 hsig->SetTitle(Form("#sigma(%s)", h2->GetTitle()));
783 histm->addHisto(hsig, id + 2);
784 }
785 };
786 for (int ioffs = 0; ioffs <= 3; ioffs++) { // vs phi, Z, pT, tgl
787 int offs = ioffs * 1000;
788 for (int iht = 0; iht < 2; iht++) { // resid, pull
789 int offsV = iht == 0 ? 0 : 5;
790 for (int il = 0; il < 8; il++) {
791 for (int iyz = 0; iyz < 2; iyz++) {
792 fitSlices(il * 10 + iyz * 100 + offsV + offs);
793 }
794 }
795 for (int ip = 0; ip < 5; ip++) {
796 fitSlices(10000 + ip * 10 + offsV + offs);
797 }
798 }
799 }
800 histm->write();
801 }
802 delete gs;
803}
804
805void CheckResidSpec::drawHistos()
806{
807 gROOT->SetBatch(true);
808 gStyle->SetTitleX(0.2);
809 gStyle->SetTitleY(0.88);
810 gStyle->SetTitleW(0.25);
811 gStyle->SetOptStat(0);
812 int nhm = mHManV.size();
813 std::array<unsigned int, 3> hcol{EColor::kRed, EColor::kBlue, EColor::kGreen + 2};
814 std::unique_ptr<TLegend> lg;
815 lg = std::make_unique<TLegend>(0.12, 0.13, 0.9, 0.13 + std::min(0.5f, nhm * 0.2f / 3.f));
816 lg->SetFillStyle(0);
817 lg->SetBorderSize(0);
818 for (int i = 0; i < nhm; i++) {
819 auto hman = mHManV[i].get();
820 if (!hman || hman->GetLast() < 1) {
821 continue;
822 }
823 hman->setMarkerStyle(20 + i + (i % 2) * 4, 0.5);
824 hman->setColor(hcol[i % hcol.size()]);
825 auto le = lg->AddEntry(hman->getHisto(1), hman->GetName(), "lp");
826 le->SetTextColor(hcol[i % hcol.size()]);
827 }
828 TCanvas cly("cly", "", 600, 800), clz("clz", "", 600, 800), clpar("clpar", "", 600, 800);
829 TCanvas czly("czly", "", 600, 800), czlz("czlz", "", 600, 800), czlpar("czlpar", "", 600, 800);
831
832 auto AddLabel = [](const char* txt, float x = 0.1, float y = 0.9, int color = kBlack, float size = 0.04) {
833 TLatex* lt = new TLatex(x, y, txt);
834 lt->SetNDC();
835 lt->SetTextColor(color);
836 lt->SetTextSize(size);
837 lt->Draw();
838 return lt;
839 };
840
841 auto drawResLr = [this](TCanvas& canv, int offs, const float resMM[8], bool logX) {
842 canv.Clear();
843 canv.Divide(2, 4);
844 int nh = this->mHManV.size();
845 for (int i = 0; i < 8; i++) {
846 canv.cd(i + 1);
847 bool same = false;
848 for (int j = 0; j < nh; j++) {
849 auto hman = this->mHManV[j].get();
850 if (!hman || hman->GetLast() < 1) {
851 continue;
852 }
853 if (auto histo = hman->getHisto(10 * i + offs)) {
854 histo->Draw(same ? "same" : "");
855 if (!same) {
856 histo->SetMinimum(-resMM[i]);
857 histo->SetMaximum(resMM[i]);
858 same = true;
859 }
860 }
861 }
862 gPad->SetGrid();
863 gPad->SetLogx(logX);
864 }
865 };
866
867 auto drawResPar = [this](TCanvas& canv, int offs, const float resMM[8], bool logX) {
868 canv.Clear();
869 canv.Divide(2, 3);
870 int nh = this->mHManV.size();
871 for (int i = 0; i < 5; i++) {
872 canv.cd(i + 1);
873 bool same = false;
874 for (int j = 0; j < nh; j++) {
875 auto hman = this->mHManV[j].get();
876 if (!hman || hman->GetLast() < 1) {
877 continue;
878 }
879 if (auto histo = hman->getHisto(10 * i + offs)) {
880 histo->Draw(same ? "same" : "");
881 if (!same) {
882 histo->SetMinimum(-resMM[i]);
883 histo->SetMaximum(resMM[i]);
884 same = true;
885 }
886 }
887 }
888 gPad->SetGrid();
889 gPad->SetLogx(logX);
890 }
891 };
892
893 cly.Print(Form("%s_hman.pdf[", params.outname.c_str()));
894 drawResLr(cly, 1, params.resMMLrY, false);
895 cly.cd(2);
896 lg->Draw();
897 AddLabel("Y residuals", 0.1, 0.95);
898 cly.Print(Form("%s_hman.pdf", params.outname.c_str()));
899
900 drawResLr(clz, 101, params.resMMLrZ, false);
901 clz.cd(2);
902 lg->Draw();
903 AddLabel("Z residuals", 0.1, 0.95);
904 clz.Print(Form("%s_hman.pdf", params.outname.c_str()));
905
906 drawResLr(czly, 1001, params.resMMLrY, false);
907 czly.cd(2);
908 lg->Draw();
909 AddLabel("Y residuals", 0.1, 0.95);
910 czly.Print(Form("%s_hman.pdf", params.outname.c_str()));
911
912 drawResLr(czlz, 1101, params.resMMLrZ, false);
913 czlz.cd(2);
914 lg->Draw();
915 AddLabel("Z residuals", 0.1, 0.95);
916 czlz.Print(Form("%s_hman.pdf", params.outname.c_str()));
917
918 drawResLr(czly, 2001, params.resMMLrY, true);
919 czly.cd(2);
920 lg->Draw();
921 AddLabel("Y residuals", 0.1, 0.95);
922 czly.Print(Form("%s_hman.pdf", params.outname.c_str()));
923
924 drawResLr(czlz, 2101, params.resMMLrZ, true);
925 czlz.cd(2);
926 lg->Draw();
927 AddLabel("Z residuals", 0.1, 0.95);
928 czlz.Print(Form("%s_hman.pdf", params.outname.c_str()));
929
930 drawResLr(czly, 3001, params.resMMLrY, false);
931 czly.cd(2);
932 lg->Draw();
933 AddLabel("Y residuals", 0.1, 0.95);
934 czly.Print(Form("%s_hman.pdf", params.outname.c_str()));
935
936 drawResLr(czlz, 3101, params.resMMLrZ, false);
937 czlz.cd(2);
938 lg->Draw();
939 AddLabel("Z residuals", 0.1, 0.95);
940 czlz.Print(Form("%s_hman.pdf", params.outname.c_str()));
941
942 drawResPar(clpar, 10001, params.resMMPar, false);
943 clpar.cd(6);
944 lg->Draw();
945 AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8);
946 clpar.Print(Form("%s_hman.pdf", params.outname.c_str()));
947
948 drawResPar(czlpar, 11001, params.resMMPar, false);
949 czlpar.cd(6);
950 lg->Draw();
951 AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8);
952 czlpar.Print(Form("%s_hman.pdf", params.outname.c_str()));
953
954 drawResPar(czlpar, 12001, params.resMMPar, true);
955 czlpar.cd(6);
956 lg->Draw();
957 AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8);
958 czlpar.Print(Form("%s_hman.pdf", params.outname.c_str()));
959
960 drawResPar(czlpar, 13001, params.resMMPar, false);
961 czlpar.cd(6);
962 lg->Draw();
963 AddLabel("IB-OB tracks params differences at R = 12 cm", 0.2, 0.8);
964 czlpar.Print(Form("%s_hman.pdf", params.outname.c_str()));
965
966 cly.Print(Form("%s_hman.pdf]", params.outname.c_str()));
967}
968
970{
971 mDBGOut.reset();
972 if (mHManV.size()) {
973 postProcessHistos();
974 }
975 if (mDraw) {
976 drawHistos();
977 }
978}
979
981{
983 return;
984 }
985 if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) {
986 LOG(info) << "Imposing new MeanVertex: " << ((const o2::dataformats::MeanVertexObject*)obj)->asString();
987 mMeanVtx = *(const o2::dataformats::MeanVertexObject*)obj;
988 mMeanVertexUpdated = true;
989 return;
990 }
991 if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) {
992 LOG(info) << "cluster dictionary updated";
993 mITSDict = (const o2::itsmft::TopologyDictionary*)obj;
994 return;
995 }
996}
997
998DataProcessorSpec getCheckResidSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool drawOnly, bool postProcOnly, bool itsStag)
999{
1000 std::vector<OutputSpec> outputs;
1001 auto dataRequest = std::make_shared<DataRequest>();
1002 dataRequest->setITSPerLayer(itsStag);
1003 if (!drawOnly && !postProcOnly) {
1004 bool useMC = false;
1005 dataRequest->requestTracks(srcTracks, useMC);
1006 dataRequest->requestClusters(srcClusters, useMC);
1007 dataRequest->requestPrimaryVertices(useMC);
1008 dataRequest->inputs.emplace_back("meanvtx", "GLO", "MEANVERTEX", 0, Lifetime::Condition, ccdbParamSpec("GLO/Calib/MeanVertex", {}, 1));
1009 }
1010 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
1011 true, // GRPECS=true
1012 true, // GRPLHCIF
1013 true, // GRPMagField
1014 true, // askMatLUT
1016 dataRequest->inputs, true);
1017 Options opts;
1018 if (!drawOnly) {
1019 opts = Options{
1020 {"nthreads", VariantType::Int, 1, {"number of threads"}},
1021 {"no-tree", VariantType::Bool, false, {"do not fill residuals tree"}},
1022 {"no-hist", VariantType::Bool, false, {"do not fill residuals histograms"}},
1023 {"draw-report", VariantType::Bool, false, {"fill residuals report"}},
1024 };
1025 }
1026
1027 return DataProcessorSpec{
1028 "check-resid",
1029 dataRequest->inputs,
1030 outputs,
1031 AlgorithmSpec{adaptFromTask<CheckResidSpec>(dataRequest, ggRequest, srcTracks, drawOnly, postProcOnly)},
1032 opts};
1033}
1034
1035} // 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
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
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
const GLdouble * v
Definition glcorearb.h:832
GLdouble f
Definition glcorearb.h:310
GLint y
Definition glcorearb.h:270
GLenum const GLfloat * params
Definition glcorearb.h:272
GLuint id
Definition glcorearb.h:650
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
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
const TrackingFrameInfo *const const Cluster *const const float const float bz
return true
const bool const int TrackITSInternal< NLayers > & track
double * getX(double *xyDxy, int N)
double * getY(double *xyDxy, int N)
TrackParCovF TrackParCov
Definition Track.h:33
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
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)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"