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.
unsigned short int uint16_t
int32_t i
int32_t retVal
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events Show standalone event Run event generator maximum time bin of continuous for triggered for automatic continuous for automatic continuous triggered uint64_t
configStandalone Reconstruction rec_tpc float
std::vector< o2::its::TrackITS > tracks
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
GLint first
Definition glcorearb.h:399
GLint y
Definition glcorearb.h:270
GLenum GLfloat param
Definition glcorearb.h:271
float to02PiGen(float phi)
Definition Utils.h:70
Global TPC definitions and constants.
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