Project
Loading...
Searching...
No Matches
EventTimeMaker.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
19
20#include "TRandom.h"
21#include "TMath.h"
23#include "TOFBase/Geo.h"
24
26
27namespace o2
28{
29
30namespace tof
31{
32
33int eventTimeContainer::maxNtracksInSet = -1;
34// usefull constants
35constexpr unsigned long combinatorial[20] = {1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049, 177147, 531441, 1594323, 4782969, 14348907, 43046721, 129140163, 387420489, 1162261467};
36//---------------
37
38void computeEvTime(const std::vector<eventTimeTrack>& tracks, const std::vector<int>& trkIndex, eventTimeContainer& evtime)
39{
40 static constexpr int maxNumberOfSets = 200;
41 static constexpr float weightLimit = 1E-6; // Limit in the weights
42
43 const int ntracks = tracks.size();
44 LOG(debug) << "For the collision time using " << ntracks << " tracks";
45
46 // find the int BC as the more frequent BC
47 std::map<int, int> bcCand;
48 for (const auto& trk : tracks) {
49 int bc = int(trk.tofSignal() * o2::tof::Geo::BC_TIME_INPS_INV);
50 bcCand[bc]++;
51 }
52
53 int maxcount = 0;
54 int maxbc = 0;
55 for (const auto& [bc, count] : bcCand) {
56 if (count > maxcount) {
57 maxbc = bc;
58 maxcount = count;
59 }
60 }
61
62 double t0fill = maxbc * o2::tof::Geo::BC_TIME_INPS;
63
64 // LOG(info) << "Int bc candidate from TOF : " << maxbc << " - time_in_ps = " << t0fill;
65
66 if (ntracks < 2) { // at least 2 tracks required
67 LOG(debug) << "Skipping event because at least 2 tracks are required";
68 return;
69 }
70
71 const int maxNtrackInSet = evtime.getMaxNtracksInSet();
72 int hypo[maxNtrackInSet];
73
74 int nmaxtracksinset = ntracks > 22 ? 6 : maxNtrackInSet; // max number of tracks in a set for event time computation
75 // int nmaxtracksinset = maxNtrackInSet;
76
77 LOG(debug) << "nmaxtracksinset " << nmaxtracksinset;
78 int ntracksinset = std::min(ntracks, nmaxtracksinset);
79 LOG(debug) << "ntracksinset " << ntracksinset;
80
81 int nset = ((ntracks - 1) / ntracksinset) + 1;
82 LOG(debug) << "nset " << nset;
83 int ntrackUsable = ntracks;
84 LOG(debug) << "ntrackUsable " << ntrackUsable;
85
86 if (nset > maxNumberOfSets) {
87 nset = maxNumberOfSets;
88 LOG(debug) << "resetting nset " << nset;
89 ntrackUsable = nmaxtracksinset * nset;
90 LOG(debug) << "resetting ntrackUsable " << ntrackUsable;
91 }
92
93 // list of tracks in set
94 std::vector<int> trackInSet[maxNumberOfSets];
95
96 for (int i = 0; i < ntrackUsable; i++) {
97 int iset = i % nset;
98
99 trackInSet[iset].push_back(i);
100 }
101
102 int status;
103 // compute event time for each set
104 for (int iset = 0; iset < nset; iset++) {
105 LOG(debug) << "iset " << iset << " has size " << trackInSet[iset].size();
106 unsigned long bestComb = 0;
107 while (!(status = getStartTimeInSet(tracks, trackInSet[iset], bestComb, t0fill))) {
108 ;
109 }
110 if (status == 1) {
111 int ntracks = trackInSet[iset].size();
112 // set the best in set
113 for (int itrk = 0; itrk < ntracks; itrk++) {
114 hypo[itrk] = bestComb % 3;
115 bestComb /= 3;
116
117 int index = trkIndex[trackInSet[iset][itrk]];
118 const eventTimeTrack& ctrack = tracks[trackInSet[iset][itrk]];
119 LOG(debug) << "Using hypothesis: " << hypo[itrk] << " tofSignal: " << ctrack.mSignal << " exp. time: " << ctrack.expTimes[hypo[itrk]] << " exp. sigma: " << ctrack.expSigma[hypo[itrk]];
120 LOG(debug) << "0= " << ctrack.expTimes[0] << " +- " << ctrack.expSigma[0] << " 1= " << ctrack.expTimes[1] << " +- " << ctrack.expSigma[1] << " 2= " << ctrack.expTimes[2] << " +- " << ctrack.expSigma[2];
121
122 evtime.mWeights[index] = 1. / (ctrack.expSigma[hypo[itrk]] * ctrack.expSigma[hypo[itrk]]);
123 evtime.mTrackTimes[index] = ctrack.mSignal - ctrack.expTimes[hypo[itrk]];
124 }
125 }
126 LOG(debug) << "iset " << iset << " did not have good status";
127 } // end loop in set
128
129 // do average among all tracks
130 int worse = 0;
131 int nRemoved = 0;
132 double finalTime = 0, allweights = 0;
133 int ntrackUsed = 0;
134 while (worse > -1) {
135 float errworse = EventTimeTOFParams::Instance().maxNsigma;
136 finalTime = 0, allweights = 0;
137 ntrackUsed = 0;
138 worse = -1;
139 for (int i = 0; i < evtime.mWeights.size(); i++) {
140 if (evtime.mWeights[i] < weightLimit) {
141 continue;
142 }
143 ntrackUsed++;
144 allweights += evtime.mWeights[i];
145 finalTime += evtime.mTrackTimes[i] * evtime.mWeights[i];
146 }
147
148 double averageBest = finalTime / allweights;
149 for (int i = 0; i < evtime.mWeights.size(); i++) {
150 if (evtime.mWeights[i] < weightLimit) {
151 continue;
152 }
153 float err = evtime.mTrackTimes[i] - averageBest;
154 err *= sqrt(evtime.mWeights[i]);
155 err = std::abs(err);
156 if (err > errworse) {
157 errworse = err;
158 worse = i;
159 }
160 }
161 if (worse > -1) { // remove track
162 // LOG(info) << "err " << errworse;
163 evtime.mWeights[worse] = 0;
164 nRemoved++;
165 }
166 }
167
168 LOG(debug) << "Removed " << nRemoved << " tracks from start time calculation";
169
170 if (allweights < weightLimit) {
171 LOG(debug) << "Skipping because allweights " << allweights << " are lower than " << weightLimit;
172 return;
173 }
174
175 evtime.mEventTime = finalTime / allweights;
176 evtime.mEventTimeError = sqrt(1. / allweights);
177 evtime.mEventTimeMultiplicity = ntrackUsed;
178}
179
180void computeEvTimeFast(const std::vector<eventTimeTrack>& tracks, const std::vector<int>& trkIndex, eventTimeContainer& evtime)
181{
182 static constexpr int maxNumberOfSets = 200;
183 static constexpr float weightLimit = 1E-6; // Limit in the weights
184
185 const int ntracks = tracks.size();
186 LOG(debug) << "For the collision time using " << ntracks;
187
188 if (ntracks < 2) { // at least 2 tracks required
189 LOG(debug) << "Skipping event because at least 2 tracks are required";
190 return;
191 }
192 const int maxNtrackInSet = evtime.getMaxNtracksInSet();
193
194 int hypo[maxNtrackInSet];
195
196 int nmaxtracksinset = ntracks > 22 ? 6 : maxNtrackInSet; // max number of tracks in a set for event time computation
197 int ntracksinset = std::min(ntracks, nmaxtracksinset);
198
199 int nset = ((ntracks - 1) / ntracksinset) + 1;
200 int ntrackUsable = ntracks;
201
202 if (nset > maxNumberOfSets) {
203 nset = maxNumberOfSets;
204 ntrackUsable = nmaxtracksinset * nset;
205 }
206
207 // list of tracks in set
208 std::vector<int> trackInSet[maxNumberOfSets];
209
210 for (int i = 0; i < ntrackUsable; i++) {
211 int iset = i % nset;
212
213 trackInSet[iset].push_back(i);
214 }
215
216 int status;
217 // compute event time for each set
218 for (int iset = 0; iset < nset; iset++) {
219 unsigned long bestComb = 0;
220 while (!(status = getStartTimeInSetFast(tracks, trackInSet[iset], bestComb))) {
221 ;
222 }
223 if (status == 1) {
224 int ntracks = trackInSet[iset].size();
225 // set the best in set
226 for (int itrk = 0; itrk < ntracks; itrk++) {
227 hypo[itrk] = bestComb % 3;
228 bestComb /= 3;
229
230 int index = trkIndex[trackInSet[iset][itrk]];
231 const eventTimeTrack& ctrack = tracks[trackInSet[iset][itrk]];
232 LOG(debug) << "Using hypothesis: " << hypo[itrk] << " tofSignal: " << ctrack.mSignal << " exp. time: " << ctrack.expTimes[hypo[itrk]] << " exp. sigma: " << ctrack.expSigma[hypo[itrk]];
233 LOG(debug) << "0= " << ctrack.expTimes[0] << " +- " << ctrack.expSigma[0] << " 1= " << ctrack.expTimes[1] << " +- " << ctrack.expSigma[1] << " 2= " << ctrack.expTimes[2] << " +- " << ctrack.expSigma[2];
234
235 evtime.mWeights[index] = 1. / (ctrack.expSigma[hypo[itrk]] * ctrack.expSigma[hypo[itrk]]);
236 evtime.mTrackTimes[index] = ctrack.mSignal - ctrack.expTimes[hypo[itrk]];
237 }
238 }
239 } // end loop in set
240
241 // do average among all tracks
242 double finalTime = 0, allweights = 0;
243 int ntrackUsed = 0;
244 for (int i = 0; i < evtime.mWeights.size(); i++) {
245 if (evtime.mWeights[i] < weightLimit) {
246 continue;
247 }
248 ntrackUsed++;
249 allweights += evtime.mWeights[i];
250 finalTime += evtime.mTrackTimes[i] * evtime.mWeights[i];
251 }
252
253 if (allweights < weightLimit) {
254 LOG(debug) << "Skipping because allweights " << allweights << " are lower than " << weightLimit;
255 return;
256 }
257
258 evtime.mEventTime = finalTime / allweights;
259 evtime.mEventTimeError = sqrt(1. / allweights);
260 evtime.mEventTimeMultiplicity = ntrackUsed;
261}
262
263int getStartTimeInSet(const std::vector<eventTimeTrack>& tracks, std::vector<int>& trackInSet, unsigned long& bestComb, double refT0)
264{
265 const auto& params = EventTimeTOFParams::Instance();
266 float errworse = params.maxNsigma;
267 const int maxNtrackInSet = eventTimeContainer::getMaxNtracksInSet();
268 float chi2, chi2best;
269 double averageBest = 0;
270 int hypo[maxNtrackInSet];
271 double starttime[maxNtrackInSet], weighttime[maxNtrackInSet];
272
273 chi2best = 10000;
274 int ntracks = trackInSet.size();
275 LOG(debug) << "Computing the start time in set with " << ntracks << " tracks";
276
277 if (ntracks < 3) {
278 LOG(debug) << "Not enough tracks!";
279 return 2; // no event time in the set
280 }
281
282 // Pre-filter: for each track, determine which hypotheses pass the time cut
283 double preStarttime[maxNtrackInSet][3];
284 double preWeighttime[maxNtrackInSet][3];
285 int validHypo[maxNtrackInSet][3]; // which hypothesis indices are valid
286 int nValidHypo[maxNtrackInSet]; // how many valid hypotheses per track
287
288 unsigned long ncombReduced = 1;
289 for (int itrk = 0; itrk < ntracks; itrk++) {
290 const eventTimeTrack& ctrack = tracks[trackInSet[itrk]];
291 nValidHypo[itrk] = 0;
292 for (int h = 0; h < 3; h++) {
293 double st = ctrack.mSignal - ctrack.expTimes[h];
294 if (std::abs(st - refT0) < 2000) {
295 int idx = nValidHypo[itrk];
296 validHypo[itrk][idx] = h;
297 preStarttime[itrk][idx] = st;
298 preWeighttime[itrk][idx] = 1. / (ctrack.expSigma[h] * ctrack.expSigma[h]);
299 nValidHypo[itrk]++;
300 }
301 }
302 if (nValidHypo[itrk] == 0) {
303 // No valid hypothesis for this track; treat as 1 entry with zero weight
304 // to keep combination enumeration simple
305 validHypo[itrk][0] = 0;
306 preStarttime[itrk][0] = 0;
307 preWeighttime[itrk][0] = 0;
308 nValidHypo[itrk] = 1;
309 }
310 ncombReduced *= nValidHypo[itrk];
311 }
312
313 // Enumerate only valid hypothesis combinations
314 for (unsigned long comb = 0; comb < ncombReduced; comb++) {
315 unsigned long curr = comb;
316
317 int ngood = 0;
318 double average = 0;
319 double sumweights = 0;
320 // Decode the combination using per-track valid hypothesis counts
321 unsigned long origComb = 0;
322 unsigned long origBase = 1;
323 for (int itrk = 0; itrk < ntracks; itrk++) {
324 int localIdx = curr % nValidHypo[itrk];
325 curr /= nValidHypo[itrk];
326 int h = validHypo[itrk][localIdx];
327 hypo[itrk] = h;
328 origComb += h * origBase;
329 origBase *= 3;
330 starttime[itrk] = preStarttime[itrk][localIdx];
331 weighttime[itrk] = preWeighttime[itrk][localIdx];
332
333 if (weighttime[itrk] > 0) {
334 average += starttime[itrk] * weighttime[itrk];
335 sumweights += weighttime[itrk];
336 ngood++;
337 }
338 }
339
340 if (ngood < 2) {
341 continue;
342 }
343
344 average /= sumweights;
345
346 // compute chi2
347 chi2 = 0;
348 double deltat;
349 for (int itrk = 0; itrk < ntracks; itrk++) {
350 deltat = starttime[itrk] - average;
351 chi2 += deltat * deltat * weighttime[itrk];
352 }
353 chi2 /= (ngood - 1);
354
355 if (chi2 < chi2best) {
356 bestComb = origComb;
357 chi2best = chi2;
358 averageBest = average;
359 }
360 } // end loop in combinations
361
362 int worse = -1;
363 // check the best combination
364 unsigned long curr = bestComb;
365 for (int itrk = 0; itrk < ntracks; itrk++) {
366 hypo[itrk] = curr % 3;
367 curr /= 3;
368
369 const eventTimeTrack& ctrack = tracks[trackInSet[itrk]];
370 float err = ctrack.mSignal - ctrack.expTimes[hypo[itrk]] - averageBest;
371 err /= ctrack.expSigma[hypo[itrk]];
372 err = std::abs(err);
373 if (err > errworse) {
374 errworse = err;
375 worse = itrk;
376 }
377 }
378
379 if (worse > -1) {
380 const eventTimeTrack& ctrack = tracks[trackInSet[worse]];
381 // remove the track and try again
382 trackInSet.erase(trackInSet.begin() + worse);
383 return 0;
384 }
385
386 return 1; // good event time in the set
387}
388
389int getStartTimeInSetFast(const std::vector<eventTimeTrack>& tracks, std::vector<int>& trackInSet, unsigned long& bestComb)
390{
391 const int maxNtrackInSet = eventTimeContainer::getMaxNtracksInSet();
392 float chi2, chi2best;
393 double averageBest = 0;
394 int hypo[maxNtrackInSet];
395 double starttime[maxNtrackInSet], weighttime[maxNtrackInSet];
396
397 chi2best = 10000;
398 int ntracks = trackInSet.size();
399
400 if (ntracks < 3) {
401 return 2; // no event time in the set
402 }
403
404 unsigned long ncomb = combinatorial[ntracks];
405
406 unsigned long comb = 0; // use only pions
407
408 int ngood = 0;
409 double average = 0;
410 double sumweights = 0;
411
412 // get track info in the set for current combination
413 for (int itrk = 0; itrk < ntracks; itrk++) {
414 hypo[itrk] = 0;
415 const eventTimeTrack& ctrack = tracks[trackInSet[itrk]];
416 starttime[itrk] = ctrack.mSignal - ctrack.expTimes[hypo[itrk]];
417 weighttime[itrk] = 1. / (ctrack.expSigma[hypo[itrk]] * ctrack.expSigma[hypo[itrk]]);
418
419 average += starttime[itrk] * weighttime[itrk];
420 sumweights += weighttime[itrk];
421 ngood++;
422 }
423
424 average /= sumweights;
425
426 // compute chi2
427 chi2 = 0;
428 double deltat;
429 for (int itrk = 0; itrk < ntracks; itrk++) {
430 deltat = starttime[itrk] - average;
431 chi2 += deltat * deltat * weighttime[itrk];
432 }
433 chi2 /= (ngood - 1);
434
435 bestComb = comb;
436 chi2best = chi2;
437 averageBest = average;
438
439 int worse = -1;
440 float errworse = 4;
441
442 // check the best combination
443 for (int itrk = 0; itrk < ntracks; itrk++) {
444 const eventTimeTrack& ctrack = tracks[trackInSet[itrk]];
445 float err = ctrack.mSignal - ctrack.expTimes[hypo[itrk]] - averageBest;
446 err /= ctrack.expSigma[hypo[itrk]];
447 err = std::abs(err);
448 if (err > errworse) {
449 errworse = err;
450 worse = itrk;
451 }
452 }
453
454 if (worse > -1) {
455 const eventTimeTrack& ctrack = tracks[trackInSet[worse]];
456 // remove the track and try again
457 trackInSet.erase(trackInSet.begin() + worse);
458 return 0;
459 }
460
461 return 1; // good event time in the set
462}
463
464void generateEvTimeTracks(std::vector<eventTimeTrackTest>& tracks, int ntracks, float evTime)
465{
466 eventTimeTrackTest track;
467 constexpr float masses[3] = {0.13957000, 0.49367700, 0.93827200};
468 constexpr float kCSPEED = TMath::C() * 1.0e2f * 1.0e-12f;
469 float energy = 0.f;
470 float betas[3] = {0.f};
471
472 float pMismatch = ntracks * 0.00005;
473
474 for (int i = 0; i < ntracks; i++) {
475 track.mTOFChi2 = 1.f;
476 track.mP = gRandom->Exp(1);
477 track.mPt = track.mP;
478 track.mLength = 400.;
479 track.mHypo = gRandom->Exp(1);
480 if (track.mHypo > 2) {
481 track.mHypo = 2;
482 }
483 for (int j = 0; j < 3; j++) {
484 energy = sqrt(masses[j] * masses[j] + track.mP * track.mP);
485 betas[j] = track.mP / energy;
486 track.expTimes[j] = track.mLength / (betas[j] * kCSPEED);
487 track.expSigma[j] = 100.f;
488 if (j == track.mHypo) {
489 track.mSignal = track.expTimes[j] + gRandom->Gaus(0.f, track.expSigma[j]);
490
491 if (gRandom->Rndm() < pMismatch) { // assign time from a different particle
492 float p = gRandom->Exp(1);
493 float l = 400;
494 int hypo = gRandom->Exp(1);
495 if (hypo > 2) {
496 hypo = 2;
497 }
498 energy = sqrt(masses[hypo] * masses[hypo] + p * p);
499 float beta = p / energy;
500 track.mSignal = l / (beta * kCSPEED) + gRandom->Gaus(0.f, track.expSigma[j]);
501 }
502 }
503 }
504 tracks.push_back(track);
505 }
506}
507
508} // namespace tof
509} // namespace o2
#define O2ParamImpl(classname)
Definition of the TOF event time maker.
std::ostringstream debug
uint64_t bc
Definition RawEventData.h:5
int32_t i
uint32_t j
Definition RawData.h:0
benchmark::State & st
Class for time synchronization of RawReader instances.
static constexpr Double_t BC_TIME_INPS
Definition Geo.h:105
static constexpr Double_t BC_TIME_INPS_INV
Definition Geo.h:106
GLint GLsizei count
Definition glcorearb.h:399
GLuint index
Definition glcorearb.h:781
GLenum const GLfloat * params
Definition glcorearb.h:272
int getStartTimeInSet(const std::vector< eventTimeTrack > &tracks, std::vector< int > &trackInSet, unsigned long &bestComb, double refT0=0)
void computeEvTimeFast(const std::vector< eventTimeTrack > &tracks, const std::vector< int > &trkIndex, eventTimeContainer &evtime)
void computeEvTime(const std::vector< eventTimeTrack > &tracks, const std::vector< int > &trkIndex, eventTimeContainer &evtime)
int getStartTimeInSetFast(const std::vector< eventTimeTrack > &tracks, std::vector< int > &trackInSet, unsigned long &bestComb)
void generateEvTimeTracks(std::vector< eventTimeTrackTest > &tracks, int ntracks, float evTime=0.0)
constexpr unsigned long combinatorial[20]
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::vector< double > mTrackTimes
weights (1/sigma^2) associated to a track in event time computation, 0 if track not used
double mEventTimeError
Value of the event time.
unsigned short mEventTimeMultiplicity
Uncertainty on the computed event time.
std::vector< float > mWeights
sum of weights of all track contributors
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"