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