Project
Loading...
Searching...
No Matches
CalibLaserTracks.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
16#include "MathUtils/Utils.h"
21#include "TLinearFitter.h"
22#include <chrono>
23#include <algorithm>
24#include <string_view>
25
26using namespace o2::tpc;
27void CalibLaserTracks::fill(std::vector<TrackTPC> const& tracks, float tp)
28{
29 fill(gsl::span(tracks.data(), tracks.size()), tp);
30}
31
32//______________________________________________________________________________
33void CalibLaserTracks::fill(const gsl::span<const TrackTPC> tracks, float tp)
34{
35 // ===| clean up TF data |===
36 mZmatchPairsTFA.clear();
37 mZmatchPairsTFC.clear();
38 mCalibDataTF.reset();
39
40 if (!tracks.size()) {
41 return;
42 }
43
44 mCalibData.nTrackTF.emplace_back();
45 mCalibDataTF.nTrackTF.emplace_back();
46
47 // ===| associate tracks with ideal laser track positions |===
48 for (const auto& track : tracks) {
49 processTrack(track);
50 }
51
52 // ===| set TF start and end times |===
53 if (mCalibData.firstTime == 0 && mCalibData.lastTime == 0) {
54 mCalibData.firstTime = mTFstart;
55 }
56
57 auto tfEnd = mTFend;
58 if (tfEnd == 0) {
59 tfEnd = mTFstart;
60 }
61 mCalibData.lastTime = tfEnd;
62
63 mCalibDataTF.firstTime = mTFstart;
64 mCalibDataTF.lastTime = tfEnd;
65
66 mAvgTP = (mAvgTP * mCalibData.processedTFs + tp) / (mCalibData.processedTFs + 1);
67 mAvgDriftV = (mAvgDriftV * mCalibData.processedTFs + mDriftV) / (mCalibData.processedTFs + 1);
68
69 // ===| TF counters |===
70 ++mCalibData.processedTFs;
71 ++mCalibDataTF.processedTFs;
72
73 // ===| finalize TF processing |===
74 endTF();
75}
76
77//______________________________________________________________________________
79{
80 if (track.hasBothSidesClusters()) {
81 return;
82 }
83
84 // use outer parameters which are closest to the laser mirrors
85 auto parOutAtLtr = track.getOuterParam();
86
87 // track should have been alreay propagated close to the laser mirrors
88 if (parOutAtLtr.getX() < 220) {
89 return;
90 }
91
92 // recalculate z position based on trigger or CE position if needed
93 float zTrack = parOutAtLtr.getZ();
94
95 // TODO: calculation has to be improved
96 if (mTriggerPos < 0) {
97 // use CE for time 0
98 const float zOffset = (track.getTime0() + mTriggerPos) * mZbinWidth * mDriftV + 250;
99 // printf("time0: %.2f, trigger pos: %d, zTrack: %.2f, zOffset: %.2f\n", track.getTime0(), mTriggerPos, zTrack, zOffset);
100 zTrack += zOffset;
101 parOutAtLtr.setZ(zTrack);
102 } else if (mTriggerPos > 0) {
103 const float zOffset = mTriggerPos;
104 }
105
106 if (std::abs(zTrack) > 300) {
107 return;
108 }
109
110 // try association with ideal laser track and rotate parameters
111 const int side = track.hasCSideClusters();
112 const int laserTrackID = findLaserTrackID(parOutAtLtr, side);
113
114 if (laserTrackID < 0 || laserTrackID >= LaserTrack::NumberOfTracks) {
115 return;
116 }
117
118 auto ltr = mLaserTracks.getTrack(laserTrackID);
119 parOutAtLtr.rotateParam(ltr.getAlpha());
120 parOutAtLtr.propagateParamTo(ltr.getX(), mBz);
121
122 if (ltr.getSide() == 0) {
123 mZmatchPairsA.emplace_back(TimePair{ltr.getZ(), parOutAtLtr.getZ(), mTFstart});
124 mZmatchPairsTFA.emplace_back(TimePair{ltr.getZ(), parOutAtLtr.getZ(), mTFstart});
125 } else {
126 mZmatchPairsC.emplace_back(TimePair{ltr.getZ(), parOutAtLtr.getZ(), mTFstart});
127 mZmatchPairsTFC.emplace_back(TimePair{ltr.getZ(), parOutAtLtr.getZ(), mTFstart});
128 }
129
130 mCalibData.matchedLtrIDs.emplace_back(laserTrackID);
131 mCalibDataTF.matchedLtrIDs.emplace_back(laserTrackID);
132
133 const auto dEdx = track.getdEdx().dEdxTotTPC;
134 mCalibData.dEdx.emplace_back(dEdx);
135 mCalibDataTF.dEdx.emplace_back(dEdx);
136
137 ++mCalibData.nTrackTF.back();
138 ++mCalibDataTF.nTrackTF.back();
139
140 // ===| debug output |========================================================
141 if (mWriteDebugTree) {
142 if (!mDebugStream) {
143 mDebugStream = std::make_unique<o2::utils::TreeStreamRedirector>(mDebugOutputName.data(), "recreate");
144 }
145
146 auto writeTrack = track;
147 *mDebugStream << "ltrMatch"
148 << "tfStart=" << mTFstart
149 << "tfEnd=" << mTFend
150 << "ltr=" << ltr // matched ideal laser track
151 << "trOutLtr=" << parOutAtLtr // track rotated and propagated to ideal track position
152 << "TPCTracks=" << writeTrack // original TPC track
153 << "mDriftV=" << mDriftV
154 << "laserTrackID=" << laserTrackID
155 << "\n";
156 }
157}
158
159//______________________________________________________________________________
160int CalibLaserTracks::findLaserTrackID(TrackPar outerParam, int side)
161{
162 // ===| rotate outer param to closes laser rod |===
163 const auto phisec = getPhiNearbyLaserRod(outerParam, side);
164 if (!outerParam.rotateParam(phisec)) {
165 return -1;
166 }
167
168 if (side < 0) {
169 side = outerParam.getZ() < 0;
170 }
171
172 // ===| laser rod |===
173 const int rod = std::nearbyint((phisec - LaserTrack::FirstRodPhi[side]) / LaserTrack::RodDistancePhi);
174
175 // ===| laser bundle |===
176 float mindist = 1000;
177
178 const auto outerParamZ = std::abs(outerParam.getZ());
179
180 int bundle = -1;
181 for (size_t i = 0; i < LaserTrack::CoarseBundleZPos.size(); ++i) {
182 const float dist = std::abs(outerParamZ - LaserTrack::CoarseBundleZPos[i]);
183 if (dist < mindist) {
184 mindist = dist;
185 bundle = i;
186 }
187 }
188
189 if (bundle < 0) {
190 return -1;
191 }
192
193 // ===| laser beam |===
194 const auto outerParamsInBundle = mLaserTracks.getTracksInBundle(side, rod, bundle);
195 mindist = 1000;
196
197 int beam = -1;
198 for (int i = 0; i < outerParamsInBundle.size(); ++i) {
199 const auto louterParam = outerParamsInBundle[i];
200 if (i == 0) {
201 outerParam.propagateParamTo(louterParam.getX(), mBz);
202 }
203 const float dist = std::abs(outerParam.getSnp() - louterParam.getSnp());
204 if (dist < mindist) {
205 mindist = dist;
206 beam = i;
207 }
208 }
209
210 if (mindist > 0.01) {
211 return -1;
212 }
213
214 // ===| track ID from side, rod, bundle and beam |===
215 const int trackID = LaserTrack::NumberOfTracks / 2 * side +
218 beam;
219
220 return trackID;
221}
222
223//______________________________________________________________________________
225{
226 const auto xyzGlo = param.getXYZGlo();
227 const auto phiTrack = o2::math_utils::to02PiGen(std::atan2(xyzGlo.Y(), xyzGlo.X()) - LaserTrack::FirstRodPhi[side % 2]);
229
230 return phiRod;
231}
232
233//______________________________________________________________________________
235{
236 const auto xyzGlo = param.getXYZGlo();
237 const auto phiTrack = o2::math_utils::to02PiGen(std::atan2(xyzGlo.Y(), xyzGlo.X()) - LaserTrack::FirstRodPhi[side % 2]);
238 const auto phiRod = o2::math_utils::to02PiGen(std::nearbyint(phiTrack / LaserTrack::RodDistancePhi) * LaserTrack::RodDistancePhi);
239
240 return std::abs(phiRod - phiTrack) < LaserTrack::SectorSpanRad / 4.;
241}
242
243//______________________________________________________________________________
244void CalibLaserTracks::updateParameters()
245{
246 const auto& gasParam = ParameterGas::Instance();
247 const auto& electronicsParam = ParameterElectronics::Instance();
248 const auto& detpar = o2::tpc::ParameterDetector::Instance();
249 mDriftV = gasParam.DriftV;
250 mZbinWidth = electronicsParam.ZbinWidth;
251 mTOffsetMUS = detpar.DriftTimeOffset * mZbinWidth;
252}
253
254//______________________________________________________________________________
256{
257 if (!other) {
258 return;
259 }
260 mCalibData.processedTFs += other->mCalibData.processedTFs;
261
262 const auto sizeAthis = mZmatchPairsA.size();
263 const auto sizeCthis = mZmatchPairsC.size();
264 const auto sizeAother = other->mZmatchPairsA.size();
265 const auto sizeCother = other->mZmatchPairsC.size();
266
267 mZmatchPairsA.insert(mZmatchPairsA.end(), other->mZmatchPairsA.begin(), other->mZmatchPairsA.end());
268 mZmatchPairsC.insert(mZmatchPairsC.end(), other->mZmatchPairsC.begin(), other->mZmatchPairsC.end());
269
270 auto& ltrIDs = mCalibData.matchedLtrIDs;
271 auto& ltrIDsOther = other->mCalibData.matchedLtrIDs;
272 ltrIDs.insert(ltrIDs.end(), ltrIDsOther.begin(), ltrIDsOther.end());
273
274 auto& nTrk = mCalibData.nTrackTF;
275 auto& nTrkOther = other->mCalibData.nTrackTF;
276 nTrk.insert(nTrk.end(), nTrkOther.begin(), nTrkOther.end());
277
278 auto& dEdx = mCalibData.dEdx;
279 auto& dEdxOther = other->mCalibData.dEdx;
280 dEdx.insert(dEdx.end(), dEdxOther.begin(), dEdxOther.end());
281
282 mCalibData.firstTime = std::min(mCalibData.firstTime, other->mCalibData.firstTime);
283 mCalibData.lastTime = std::max(mCalibData.lastTime, other->mCalibData.lastTime);
284
285 if ((mAvgTP > 0) && (other->mAvgTP > 0)) {
286 mAvgTP = (mAvgTP + other->mAvgTP) / 2.0;
287 } else if (other->mAvgTP > 0) {
288 mAvgTP = other->mAvgTP;
289 }
290
291 if ((mAvgDriftV > 0) && (other->mAvgDriftV > 0)) {
292 mAvgDriftV = (mAvgDriftV + other->mAvgDriftV) / 2.0;
293 } else if (other->mAvgDriftV > 0) {
294 mAvgDriftV = other->mAvgDriftV;
295 }
296
297 sort(mZmatchPairsA);
298 sort(mZmatchPairsC);
299
300 LOGP(info, "Merged CalibLaserTracks with mached pairs {} / {} + {} / {} = {} / {} (this +_other A- / C-Side)", sizeAthis, sizeCthis, sizeAother, sizeCother, mZmatchPairsA.size(), mZmatchPairsC.size());
301}
302
303//______________________________________________________________________________
305{
306 LOGP(info, "Ending time frame {} - {} with {} / {} matched laser tracks (total: {} / {}) on the A / C-Side", mTFstart, mTFend, mZmatchPairsTFA.size(), mZmatchPairsTFC.size(), mZmatchPairsA.size(), mZmatchPairsC.size());
307 fillCalibData(mCalibDataTF, mZmatchPairsTFA, mZmatchPairsTFC);
308
309 if (mDebugStream) {
310 (*mDebugStream) << "tfData"
311 << "tfStart=" << mTFstart
312 << "tfEnf=" << mTFend
313 << "zPairsA=" << mZmatchPairsTFA
314 << "zPairsC=" << mZmatchPairsTFC
315 << "calibData=" << mCalibDataTF
316 << "mDriftV=" << mDriftV
317 << "\n";
318 }
319}
320
321//______________________________________________________________________________
323{
324 mFinalized = true;
325 sort(mZmatchPairsA);
326 sort(mZmatchPairsC);
327
328 fillCalibData(mCalibData, mZmatchPairsA, mZmatchPairsC);
329
330 // auto& ltrIDs = mCalibData.matchedLtrIDs;
331 // std::sort(ltrIDs.begin(), ltrIDs.end());
332 // ltrIDs.erase(std::unique(ltrIDs.begin(), ltrIDs.end()), ltrIDs.end());
333
334 if (mDebugStream) {
335 (*mDebugStream) << "finalData"
336 << "zPairsA=" << mZmatchPairsA
337 << "zPairsC=" << mZmatchPairsC
338 << "calibData=" << mCalibData
339 << "\n";
340
341 mDebugStream->Close();
342 }
343}
344
345//______________________________________________________________________________
346void CalibLaserTracks::fillCalibData(LtrCalibData& calibData, const std::vector<TimePair>& pairsA, const std::vector<TimePair>& pairsC)
347{
348 auto dvA = fit(pairsA, "A-Side");
349 auto dvC = fit(pairsC, "C-Side");
350 calibData.creationTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
351 calibData.refVDrift = mAvgDriftV;
352 calibData.dvOffsetA = dvA.x1;
353 calibData.dvCorrectionA = dvA.x2;
354 calibData.nTracksA = uint16_t(pairsA.size());
355
356 calibData.dvOffsetC = dvC.x1;
357 calibData.dvCorrectionC = dvC.x2;
358 calibData.nTracksC = uint16_t(pairsC.size());
359
360 calibData.refTimeOffset = mTOffsetMUS;
361 calibData.tp = mAvgTP;
362}
363
364//______________________________________________________________________________
365TimePair CalibLaserTracks::fit(const std::vector<TimePair>& trackMatches, std::string_view info) const
366{
367 if (!trackMatches.size()) {
368 return TimePair();
369 }
370
371 static TLinearFitter fit(2, "pol1");
372 fit.StoreData(false);
373 fit.ClearPoints();
374
375 uint64_t meanTime = 0;
376 double minZrec = 1000;
377 double maxZrec = -1000;
378 for (const auto& point : trackMatches) {
379 double x = point.x1;
380 double y = point.x2;
381 fit.AddPoint(&x, y);
382
383 meanTime += point.time;
384
385 minZrec = std::min(y, minZrec);
386 maxZrec = std::max(y, maxZrec);
387 }
388
389 meanTime /= uint64_t(trackMatches.size());
390
391 const float robustFraction = 0.9;
392 const int minPoints = 6;
393
394 if (trackMatches.size() < size_t(minPoints / robustFraction)) {
395 LOGP(warning, "{} - Not enough points to perform the fit: {} < {}", info, trackMatches.size(), size_t(minPoints / robustFraction));
396 return TimePair({0, 0, meanTime});
397 }
398 if (std::abs(maxZrec - minZrec) < 50) {
399 LOGP(warning, "{} - All points seem to be from one Layer: abs({}cm - {}cm) < 50cm, will not do fitting", info, trackMatches.size(), maxZrec, minZrec);
400 return TimePair({0, 0, meanTime});
401 }
402
403 // fit.EvalRobust(robustFraction);
404 fit.Eval();
405
407 retVal.x1 = float(fit.GetParameter(0));
408 retVal.x2 = float(fit.GetParameter(1));
409 retVal.time = meanTime;
410
411 return retVal;
412}
413
414//______________________________________________________________________________
415void CalibLaserTracks::sort(std::vector<TimePair>& trackMatches)
416{
417 std::sort(trackMatches.begin(), trackMatches.end(), [](const auto& first, const auto& second) { return first.time < second.time; });
418}
419
420//______________________________________________________________________________
422{
423 if (mFinalized) {
424 LOGP(info,
425 "Processed {} TFs from {} - {}; found tracks: {} / {}; fit offsets (cm): {} / {}; T0s (us): {} / {}; dv correction factors: {} / {} for A- / C-Side, reference: {}",
426 mCalibData.processedTFs,
427 mCalibData.firstTime,
428 mCalibData.lastTime,
429 mCalibData.nTracksA,
430 mCalibData.nTracksC,
431 mCalibData.dvOffsetA,
432 mCalibData.dvOffsetC,
433 mCalibData.getT0A(),
434 mCalibData.getT0C(),
435 mCalibData.dvCorrectionA,
436 mCalibData.dvCorrectionC,
437 mCalibData.refVDrift);
438 } else {
439 LOGP(info,
440 "Processed {} TFs from {} - {}; **Not finalized**",
441 mCalibData.processedTFs,
442 mCalibData.firstTime,
443 mCalibData.lastTime);
444
445 LOGP(info,
446 "Last processed TF from {} - {}; found tracks: {} / {}; fit offsets (cm): {} / {}; T0s (us): {} / {}; dv correction factors: {} / {} for A- / C-Side, reference: {}",
447 mCalibDataTF.firstTime,
448 mCalibDataTF.lastTime,
449 mCalibDataTF.nTracksA,
450 mCalibDataTF.nTracksC,
451 mCalibDataTF.dvOffsetA,
452 mCalibDataTF.dvOffsetC,
453 mCalibDataTF.getT0A(),
454 mCalibDataTF.getT0C(),
455 mCalibDataTF.dvCorrectionA,
456 mCalibDataTF.dvCorrectionC,
457 mCalibDataTF.refVDrift);
458 }
459}
calibration using laser tracks
General auxilliary methods.
int32_t i
int32_t retVal
Definition of the parameter class for the detector.
Definition of the parameter class for the detector electronics.
Definition of the parameter class for the detector gas.
uint32_t side
Definition RawData.h:0
void finalize()
Finalize full processing.
static float getPhiNearbyLaserRod(const TrackPar &param, int side)
calculate phi of nearest laser rod
void endTF()
End processing of this TF.
static bool hasNearbyLaserRod(const TrackPar &param, int side)
check if param is closer to a laser rod than 1/4 of a sector width
void fill(const gsl::span< const TrackTPC > tracks, float tp=0)
void processTrack(const TrackTPC &track)
process single track
void print() const
print information
void merge(const CalibLaserTracks *other)
merge data with other calibration object
void sort(std::vector< TimePair > &trackMatches)
sort TimePoint vectors
int findLaserTrackID(TrackPar track, int side=-1)
TimePair fit(const std::vector< TimePair > &trackMatches, std::string_view info) const
extract DV correction and T0 offset
LaserTrack const & getTrack(int id) const
Definition LaserTrack.h:82
gsl::span< const LaserTrack > getTracksInBundle(int side, int rod, int bundle)
get span with tracks in one bundle
Definition LaserTrack.h:92
static constexpr float SectorSpanRad
secotor width in rad
Definition LaserTrack.h:33
static constexpr int BundlesPerRod
number of micro-mirror bundle per laser rod
Definition LaserTrack.h:31
static constexpr int NumberOfTracks
Total number of laser tracks.
Definition LaserTrack.h:29
static constexpr float RodDistancePhi
phi distance of laser Rods
Definition LaserTrack.h:35
static constexpr int TracksPerBundle
number of micro-mirrors per bundle
Definition LaserTrack.h:32
static constexpr std::array< float, 4 > CoarseBundleZPos
coarse z-position of the laser bundles
Definition LaserTrack.h:36
static constexpr std::array< float, 2 > FirstRodPhi
phi pos of first laser rod, A-, C-Side
Definition LaserTrack.h:34
GLint GLenum GLint x
Definition glcorearb.h:403
GLenum GLfloat param
Definition glcorearb.h:271
float to02PiGen(float phi)
Definition Utils.h:70
Global TPC definitions and constants.
Definition SimTraits.h:167
std::vector< uint16_t > nTrackTF
number of laser tracks per TF
float dvCorrectionA
drift velocity correction factor A-Side (inverse multiplicative)
float tp
temperature over pressure ratio
float dvOffsetC
drift velocity trigger offset C-Side
float dvOffsetA
drift velocity trigger offset A-Side
float dvCorrectionC
drift velocity correction factor C-Side (inverse multiplicative)
std::vector< uint16_t > matchedLtrIDs
matched laser track IDs
std::vector< float > dEdx
dE/dx of each track
size_t processedTFs
number of processed TFs with laser track candidates
uint64_t lastTime
last time stamp of processed TFs
uint16_t nTracksC
number of tracks used for C-Side fit
long creationTime
time of creation
uint16_t nTracksA
number of tracks used for A-Side fit
float refTimeOffset
additive time offset reference (\mus)
float refVDrift
reference vdrift for which factor was extracted
uint64_t firstTime
first time stamp of processed TFs
VectorOfTObjectPtrs other