Project
Loading...
Searching...
No Matches
TrackBasedCalib.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
22#include "TRDBase/Geometry.h"
23#include "TRDBase/PadPlane.h"
28#include <cmath>
29#include <fairlogger/Logger.h>
30
31using namespace o2::trd;
32using namespace o2::trd::constants;
33
35{
36 mAngResHistos.reset();
37 mGainCalibHistos.clear();
38}
39
41{
42 bz = o2::base::Propagator::Instance()->getNominalBz();
43 mRecoParam.init(bz);
44}
45
47{
48 mTracksInITSTPCTRD = input.getITSTPCTRDTracks<TrackTRD>();
49 mTracksInTPCTRD = input.getTPCTRDTracks<TrackTRD>();
50 mTrackletsRaw = input.getTRDTracklets();
51 mTrackletsCalib = input.getTRDCalibratedTracklets();
52 mTracksTPC = input.getTPCTracks();
53 mTracksITSTPC = input.getTPCITSTracks();
54}
55
57{
58 if (!mLocalGain) {
59 LOG(alarm) << "No Local gain map available. Please upload valid object to CCDB.";
60 }
61
62 int nTracksSuccessTPCTRD = filldEdx(mTracksInTPCTRD, true);
63 int nTracksSuccessITSTPCTRD = filldEdx(mTracksInITSTPCTRD, false);
64
65 LOGP(info, "Gain Calibration: Successfully processed {} tracks ({} from ITS-TPC-TRD and {} from TPC-TRD) and collected {} data points",
66 nTracksSuccessITSTPCTRD + nTracksSuccessTPCTRD, nTracksSuccessITSTPCTRD, nTracksSuccessTPCTRD, mGainCalibHistos.size());
67}
68
70{
71 if (mTrackletsRaw.size() != mTrackletsCalib.size()) {
72 LOG(error) << "TRD raw tracklet container size differs from calibrated tracklet container size";
73 return;
74 }
75
76 if (!mNoiseCalib) {
77 LOG(alarm) << "No MCM noise map available. Please upload valid object to CCDB.";
78 }
79
80 LOGF(info, "As input tracks are available: %lu ITS-TPC-TRD tracks and %lu TPC-TRD tracks", mTracksInITSTPCTRD.size(), mTracksInTPCTRD.size());
81
83 int nTracksSuccessITSTPCTRD = doTrdOnlyTrackFits(mTracksInITSTPCTRD);
84 int nTracksSuccessTPCTRD = params.rejectTPCTRD ? 0 : doTrdOnlyTrackFits(mTracksInTPCTRD);
85
86 LOGF(info, "Successfully processed %i tracks (%i from ITS-TPC-TRD and %i from TPC-TRD) and collected %lu angular residuals",
87 nTracksSuccessITSTPCTRD + nTracksSuccessTPCTRD, nTracksSuccessITSTPCTRD, nTracksSuccessTPCTRD, mAngResHistos.getNEntries());
88 // mAngResHistos.print();
89}
90
91int TrackBasedCalib::filldEdx(gsl::span<const TrackTRD>& tracks, bool isTPCTRD)
92{
94 int nTracksSuccess = 0;
95 for (const auto& trkIn : tracks) {
96
97 if (trkIn.getNtracklets() < params.nTrackletsMinGainCalib) {
98 continue;
99 }
100
101 if (trkIn.getP() < params.pMin || trkIn.getP() > params.pMax) {
102 continue;
103 }
104
105 auto id = trkIn.getRefGlobalTrackId();
106 float dEdxTPC;
107 if (isTPCTRD) {
108 dEdxTPC = mTracksTPC[id].getdEdx().dEdxTotTPC;
109 } else {
110 dEdxTPC = mTracksTPC[mTracksITSTPC[id].getRefTPC()].getdEdx().dEdxTotTPC;
111 }
112 if (dEdxTPC < params.dEdxTPCMin || dEdxTPC > params.dEdxTPCMax) {
113 continue;
114 }
115
116 if (std::isnan(trkIn.getSnp())) {
117 LOG(alarm) << "Track with invalid parameters found: " << trkIn.getRefGlobalTrackId();
118 continue;
119 }
120
121 for (int iLayer = NLAYER - 1; iLayer >= 0; --iLayer) {
122 if (trkIn.getTrackletIndex(iLayer) == -1) {
123 continue;
124 }
125 if (mNoiseCalib && mNoiseCalib->isTrackletFromNoisyMCM(mTrackletsRaw[trkIn.getTrackletIndex(iLayer)])) {
126 // ignore tracklets which originate from noisy MCMs
127 continue;
128 }
129
130 // Remove split tracklets
131 if (trkIn.getIsCrossingNeighbor(iLayer)) {
132 continue;
133 }
134
135 int trkltId = trkIn.getTrackletIndex(iLayer);
136 int trkltDet = mTrackletsRaw[trkltId].getDetector();
137 int trkltSec = trkltDet / (NLAYER * NSTACK);
138
139 const auto& tracklet = mTrackletsRaw[trkltId];
140
141 auto q0 = tracklet.getQ0();
142 auto q1 = tracklet.getQ1();
143 auto q2 = tracklet.getQ2();
144 if (q0 == 0 || q1 == 0 || q2 == 0 || q0 >= 127 || q1 >= 127 || q2 >= 62) {
145 continue;
146 }
147
148 // Correction for tracklet angle
149 const auto& trackletCalib = mTrackletsCalib[trkltId];
150 float tgl = trkIn.getTgl();
151 float snp = trkIn.getSnpAt(o2::math_utils::sector2Angle(trkltSec), trackletCalib.getX(), bz);
152
153 if (std::abs(snp) > 1.) {
154 continue;
155 }
156
157 // This is the track length normalised to the track length at zero angle
158 // l/l0 = sqrt(dx^2 + dy^2 + dz^2)/dx = sqrt(1 + (dy/dx)^2 + (dz/dx)^2)
159 // (dz/dx)^2 = tan^2(lambda), (dy/dx)^2 = tan^2(phi) = sin^2(phi)/(1-sin^2(phi))
160 float trkLength = sqrt(1 + snp * snp / (1 - snp * snp) + tgl * tgl);
161 if (TMath::Abs(trkLength) < 1) {
162 LOGP(warn, "Invalid track length {} for angles snp {} and tgl {}", trkLength, snp, tgl);
163 continue;
164 }
165
166 float localGainCorr = 1.;
167 if (mLocalGain) {
168 localGainCorr = mLocalGain->getValue(trkltDet, tracklet.getPadCol(mApplyShift), tracklet.getPadRow());
169 }
170 if (TMath::Abs(localGainCorr) < 0.0001f) {
171 LOGP(warn, "Invalid localGainCorr {} for det {}, pad col {}, pad row {}", localGainCorr, trkltDet, tracklet.getPadCol(mApplyShift), tracklet.getPadRow());
172 continue;
173 }
174
175 unsigned int dEdx = (q0 + q1 + q2) / trkLength / localGainCorr;
176 if (dEdx >= NBINSGAINCALIB) {
177 continue;
178 }
179 int chamberOffset = trkltDet * NBINSGAINCALIB;
180 mGainCalibHistos.push_back(chamberOffset + dEdx);
181 }
182
183 // here we can count the number of successfully processed tracks
184 ++nTracksSuccess;
185 } // end of track loop
186 return nTracksSuccess;
187}
188
189int TrackBasedCalib::doTrdOnlyTrackFits(gsl::span<const TrackTRD>& tracks)
190{
192 int nTracksSuccess = 0;
193 for (const auto& trkIn : tracks) {
194 if (trkIn.getNtracklets() < params.nTrackletsMin) {
195 // with less than 3 tracklets the TRD-only refit not meaningful
196 if (trkIn.getNtracklets() < params.nTrackletsMinLoose || !((trkIn.getTrackletIndex(0) >= 0 && (trkIn.getTrackletIndex(NLAYER - 1) >= 0 || trkIn.getTrackletIndex(NLAYER - 2) >= 0))) || (trkIn.getTrackletIndex(1) >= 0 && trkIn.getTrackletIndex(NLAYER - 1) >= 0)) {
197 // we check if we have enough lever arm, i.e. (first and last) or (second and last) or (first and before last) are present
198 continue;
199 }
200 }
201 if (trkIn.getPt() < params.minPtCalib) {
202 // we reject low pt tracks which might suffer from multiple scattering (giving lower quality of the TRD-only fit)
203 continue;
204 }
205
206 auto trkWork = trkIn; // input is const, so we need to create a copy
207 bool trackFailed = false;
208
209 trkWork.setChi2(0.f);
210 trkWork.resetCovariance(20);
211
212 if (std::isnan(trkWork.getSnp())) {
213 LOG(alarm) << "Track with invalid parameters found: " << trkWork.getRefGlobalTrackId();
214 continue;
215 }
216
217 // reject tracks which cross sectors within TRD (if the extrapolation from the outer TRD to the outer TPC leads to a change in sector or close to the sector edges with 5 cm margin), which have larger uncertainties and probably more fakes
218 float yOuterTPC = trkIn.getOuterParam().getYAt(o2::constants::geom::XTPCOuterRef, bz);
219 if (std::fabs(yOuterTPC) > o2::constants::geom::XTPCOuterRef * tan(M_PI / 18.) - 5.) {
220 continue;
221 }
222
223 // first inward propagation (TRD track fit)
224 int currLayer = NLAYER;
225 for (int iLayer = NLAYER - 1; iLayer >= 0; --iLayer) {
226 if (trkWork.getTrackletIndex(iLayer) == -1) {
227 continue;
228 }
229 if (mNoiseCalib && mNoiseCalib->isTrackletFromNoisyMCM(mTrackletsRaw[trkWork.getTrackletIndex(iLayer)])) {
230 // ignore tracklets which originate from noisy MCMs
231 continue;
232 }
233 if (propagateAndUpdate(trkWork, iLayer, true)) {
234 trackFailed = true;
235 break;
236 }
237 currLayer = iLayer;
238 }
239 if (trackFailed) {
240 continue;
241 }
242
243 // outward propagation (smoothing)
244 for (int iLayer = currLayer + 1; iLayer < NLAYER; ++iLayer) {
245 if (trkWork.getTrackletIndex(iLayer) == -1) {
246 continue;
247 }
248 if (mNoiseCalib && mNoiseCalib->isTrackletFromNoisyMCM(mTrackletsRaw[trkWork.getTrackletIndex(iLayer)])) {
249 // ignore tracklets which originate from noisy MCMs
250 continue;
251 }
252 if (propagateAndUpdate(trkWork, iLayer, true)) {
253 trackFailed = true;
254 break;
255 }
256 currLayer = iLayer;
257 }
258 if (trackFailed) {
259 continue;
260 }
261
262 // second inward propagation (collect angular differences between tracklets + TRD track)
263 for (int iLayer = currLayer; iLayer >= 0; --iLayer) {
264 if (trkWork.getTrackletIndex(iLayer) == -1) {
265 continue;
266 }
267 if (mNoiseCalib && mNoiseCalib->isTrackletFromNoisyMCM(mTrackletsRaw[trkWork.getTrackletIndex(iLayer)])) {
268 // ignore tracklets which originate from noisy MCMs
269 continue;
270 }
271 if (propagateAndUpdate(trkWork, iLayer, false)) {
272 trackFailed = true;
273 break;
274 }
275
276 if (trkWork.getReducedChi2() > params.chi2RedMax) {
277 // set an upper bound on acceptable tracks we use for qc
278 continue;
279 }
280
281 float trkAngle = o2::math_utils::asin(trkWork.getSnp()) * TMath::RadToDeg();
282 int trkltId = trkWork.getTrackletIndex(iLayer);
283 // tracklet angle, corrected for pad tilt
284 const PadPlane* pad = Geometry::instance()->getPadPlane(mTrackletsRaw[trkltId].getDetector());
285 float tilt = tan(TMath::DegToRad() * pad->getTiltingAngle()); // tilt is signed! and returned in degrees
286 float tiltCorrUp = tilt * trkWork.getTgl() * Geometry::cdrHght();
287 float padLength = pad->getRowSize(mTrackletsRaw[trkltId].getPadRow());
288 if (!((trkWork.getSigmaZ2() < (padLength * padLength / 12.f)) && (std::fabs(mTrackletsCalib[trkltId].getZ() - trkWork.getZ()) < padLength))) {
289 tiltCorrUp = 0.f;
290 }
291
292 // use uncalibrated dy because online calibration does not work otherwise
293 float trkltDy = mTrackletsRaw[trkltId].getUncalibratedDy(30.f / o2::trd::constants::VDRIFTDEFAULT) + tiltCorrUp;
294 float trkltAngle = o2::math_utils::atan(trkltDy / Geometry::cdrHght()) * TMath::RadToDeg();
295 float angleDeviation = trkltAngle - trkAngle;
296 if (mAngResHistos.addEntry(angleDeviation, trkAngle, mTrackletsRaw[trkltId].getDetector())) {
297 // track impact angle out of histogram range
298 continue;
299 }
300 }
301
302 // here we can count the number of successfully processed tracks
303 ++nTracksSuccess;
304 } // end of track loop
305 return nTracksSuccess;
306}
307
308bool TrackBasedCalib::propagateAndUpdate(TrackTRD& trk, int iLayer, bool doUpdate) const
309{
310 // Propagates the track to TRD layer iLayer and updates the track
311 // parameters (if requested)
312 // returns 0 in case of success
313
314 auto propagator = o2::base::Propagator::Instance();
315
316 int trkltId = trk.getTrackletIndex(iLayer);
317 int trkltDet = mTrackletsRaw[trkltId].getDetector();
318 int trkltSec = trkltDet / (NLAYER * NSTACK);
319
320 if (trkltSec != o2::math_utils::angle2Sector(trk.getAlpha())) {
321 if (!trk.rotate(o2::math_utils::sector2Angle(trkltSec))) {
322 LOGF(debug, "Track could not be rotated in tracklet coordinate system");
323 return 1;
324 }
325 }
326
327 if (!propagator->PropagateToXBxByBz(trk, mTrackletsCalib[trkltId].getX(), mMaxSnp, mMaxStep, mMatCorr)) {
328 LOGF(debug, "Track propagation failed in layer %i (pt=%f, xTrk=%f, xToGo=%f)", iLayer, trk.getPt(), trk.getX(), mTrackletsCalib[trkltId].getX());
329 return 1;
330 }
331
332 if (!doUpdate) {
333 // nothing more to be done
334 return 0;
335 }
336
337 const PadPlane* pad = Geometry::instance()->getPadPlane(trkltDet);
338 float tilt = tan(TMath::DegToRad() * pad->getTiltingAngle()); // tilt is signed! and returned in degrees
339 float tiltCorrUp = tilt * (mTrackletsCalib[trkltId].getZ() - trk.getZ());
340 float zPosCorrUp = mTrackletsCalib[trkltId].getZ() + mRecoParam.getZCorrCoeffNRC() * trk.getTgl();
341 float padLength = pad->getRowSize(mTrackletsRaw[trkltId].getPadRow());
342 if (!((trk.getSigmaZ2() < (padLength * padLength / 12.f)) && (std::fabs(mTrackletsCalib[trkltId].getZ() - trk.getZ()) < padLength))) {
343 tiltCorrUp = 0.f;
344 }
345
346 std::array<float, 2> trkltPosUp{mTrackletsCalib[trkltId].getY() - tiltCorrUp, zPosCorrUp};
347 std::array<float, 3> trkltCovUp;
348 mRecoParam.recalcTrkltCov(tilt, trk.getSnp(), pad->getRowSize(mTrackletsRaw[trkltId].getPadRow()), trkltCovUp);
349
350 if (!trk.update(trkltPosUp, trkltCovUp)) {
351 LOGF(info, "Failed to update track with space point in layer %i", iLayer);
352 return 1;
353 }
354 return 0;
355}
Wrapper container for different reconstructed object types.
Global TRD definitions and constants.
Definition of the GeometryManager class.
std::ostringstream debug
Some ALICE geometry constants of common interest.
std::vector< o2::its::TrackITS > tracks
Definition of the Names Generator class.
Provides information required for TRD calibration which is based on the global tracking.
Result of refitting TPC-ITS matched track.
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:180
void init(float bz, const GPUSettingsRec *rec=nullptr)
Load parameterization for given magnetic field.
bool addEntry(float deltaAlpha, float impactAngle, int chamberId)
static Geometry * instance()
Definition Geometry.h:33
bool isTrackletFromNoisyMCM(const Tracklet64 &trklt) const
T getValue(int roc, int col, int row) const
void setInput(const o2::globaltracking::RecoContainer &input)
Initialize the input arrays.
int doTrdOnlyTrackFits(gsl::span< const TrackTRD > &tracks)
3-way fit to TRD tracklets
int filldEdx(gsl::span< const TrackTRD > &tracks, bool isTPCTRD)
Collect tracklet charges for given track.
void reset()
Reset the output.
void init()
Load geometry and apply magnetic field setting.
void calculateAngResHistos()
Main processing function for creating angular residual histograms for vDrift and ExB calibration.
bool propagateAndUpdate(TrackTRD &trk, int iLayer, bool doUpdate) const
Extrapolate track parameters to given layer and if requested perform update with tracklet.
GLenum const GLfloat * params
Definition glcorearb.h:272
GLuint id
Definition glcorearb.h:650
constexpr float XTPCOuterRef
reference radius to propagate outer TPC track
int angle2Sector(float phi)
Definition Utils.h:183
float sector2Angle(int sect)
Definition Utils.h:193
constexpr double VDRIFTDEFAULT
default value for vDrift
Definition Constants.h:81
gsl::span< const o2::trd::CalibratedTracklet > getTRDCalibratedTracklets() const
gsl::span< const o2::trd::Tracklet64 > getTRDTracklets() const
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"