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