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