Project
Loading...
Searching...
No Matches
AODProducerWorkflowSpec.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
13
40#include "MathUtils/Utils.h"
53#include "Framework/DataTypes.h"
57#include "FT0Base/Geometry.h"
82#include "ZDCBase/Constants.h"
85#include "TOFBase/Utils.h"
86#include "O2Version.h"
87#include "TMath.h"
88#include "MathUtils/Utils.h"
89#include "Math/SMatrix.h"
90#include "TString.h"
91#include <limits>
92#include <map>
93#include <numeric>
94#include <type_traits>
95#include <unordered_map>
96#include <set>
97#include <string>
98#include <vector>
99#include <thread>
100#include "TLorentzVector.h"
101#include "TVector3.h"
102#include "MathUtils/Tsallis.h"
103#include <random>
104#ifdef WITH_OPENMP
105#include <omp.h>
106#endif
107#include <filesystem>
108#include <nlohmann/json.hpp>
109
110using namespace o2::framework;
111using namespace o2::math_utils::detail;
118
119namespace o2::aodproducer
120{
121
122void AODProducerWorkflowDPL::createCTPReadout(const o2::globaltracking::RecoContainer& recoData, std::vector<o2::ctp::CTPDigit>& ctpDigits, ProcessingContext& pc)
123{
124 // Extraxt CTP Config from CCDB
125 const auto ctpcfg = pc.inputs().get<o2::ctp::CTPConfiguration*>("ctpconfig");
126 ctpcfg->printStream(std::cout);
127 // o2::ctp::CTPConfiguration ctpcfg = o2::ctp::CTPRunManager::getConfigFromCCDB(-1, std::to_string(runNumber)); // how to get run
128 // Extract inputs from recoData
129 uint64_t classMaskEMCAL = 0, classMaskTRD = 0, classMaskPHOSCPV = 0;
130 for (const auto& trgclass : ctpcfg->getCTPClasses()) {
131 if (trgclass.cluster->getClusterDetNames().find("EMC") != std::string::npos) {
132 classMaskEMCAL = trgclass.classMask;
133 }
134 if (trgclass.cluster->getClusterDetNames().find("PHS") != std::string::npos) {
135 classMaskPHOSCPV = trgclass.classMask;
136 }
137 if (trgclass.cluster->getClusterDetNames().find("TRD") != std::string::npos) {
138 classMaskTRD = trgclass.classMask;
139 }
140 }
141 LOG(info) << "createCTPReadout: Class Mask EMCAL -> " << classMaskEMCAL;
142 LOG(info) << "createCTPReadout: Class Mask PHOS/CPV -> " << classMaskPHOSCPV;
143 LOG(info) << "createCTPReadout: Class Mask TRD -> " << classMaskTRD;
144
145 // const auto& fddRecPoints = recoData.getFDDRecPoints();
146 // const auto& fv0RecPoints = recoData.getFV0RecPoints();
147 const auto& triggerrecordEMCAL = recoData.getEMCALTriggers();
148 const auto& triggerrecordPHOSCPV = recoData.getPHOSTriggers();
149 const auto& triggerrecordTRD = recoData.getTRDTriggerRecords();
150 // For EMCAL filter remove calibration triggers
151 std::vector<o2::emcal::TriggerRecord> triggerRecordEMCALPhys;
152 for (const auto& trg : triggerrecordEMCAL) {
153 if (trg.getTriggerBits() & o2::trigger::Cal) {
154 continue;
155 }
156 triggerRecordEMCALPhys.push_back(trg);
157 }
158 // const auto& triggerrecordTRD =recoData.getITSTPCTRDTriggers()
159 //
160
161 // Find TVX triggers, only TRD/EMCAL/PHOS/CPV triggers in coincidence will be accepted
162 std::set<uint64_t> bcsMapT0triggers;
163 const auto& ft0RecPoints = recoData.getFT0RecPoints();
164 for (auto& ft0RecPoint : ft0RecPoints) {
165 auto t0triggers = ft0RecPoint.getTrigger();
166 if (t0triggers.getVertex()) {
167 uint64_t globalBC = ft0RecPoint.getInteractionRecord().toLong();
168 bcsMapT0triggers.insert(globalBC);
169 }
170 }
171
172 auto genericCTPDigitizer = [&bcsMapT0triggers, &ctpDigits](auto triggerrecords, uint64_t classmask) -> int {
173 // Strategy:
174 // find detector trigger based on trigger record from readout and add CTPDigit if trigger there
175 int cntwarnings = 0;
176 uint32_t orbitPrev = 0;
177 uint16_t bcPrev = 0;
178 for (auto& trigger : triggerrecords) {
179 auto orbitPrevT = orbitPrev;
180 auto bcPrevT = bcPrev;
181 bcPrev = trigger.getBCData().bc;
182 orbitPrev = trigger.getBCData().orbit;
183 // dedicated for TRD: remove bogus triggers
184 if (orbitPrev < orbitPrevT || bcPrev >= o2::constants::lhc::LHCMaxBunches || (orbitPrev == orbitPrevT && bcPrev < bcPrevT)) {
185 cntwarnings++;
186 // LOGP(warning, "Bogus TRD trigger at bc:{}/orbit:{} (previous was {}/{}), with {} tracklets and {} digits",bcPrev, orbitPrev, bcPrevT, orbitPrevT, trig.getNumberOfTracklets(), trig.getNumberOfDigits());
187 } else {
188 uint64_t globalBC = trigger.getBCData().toLong();
189 auto t0entry = bcsMapT0triggers.find(globalBC);
190 if (t0entry != bcsMapT0triggers.end()) {
191 auto ctpdig = std::find_if(ctpDigits.begin(), ctpDigits.end(), [globalBC](const o2::ctp::CTPDigit& dig) { return static_cast<uint64_t>(dig.intRecord.toLong()) == globalBC; });
192 if (ctpdig != ctpDigits.end()) {
193 // CTP digit existing from other trigger, merge detector class mask
194 ctpdig->CTPClassMask |= std::bitset<64>(classmask);
195 LOG(debug) << "createCTPReadout: Merging " << classmask << " CTP digits with existing digit, CTP mask " << ctpdig->CTPClassMask;
196 } else {
197 // New CTP digit needed
198 LOG(debug) << "createCTPReadout: New CTP digit needed for class " << classmask << std::endl;
199 auto& ctpdigNew = ctpDigits.emplace_back();
200 ctpdigNew.intRecord.setFromLong(globalBC);
201 ctpdigNew.CTPClassMask = classmask;
202 }
203 } else {
204 LOG(warning) << "createCTPReadout: Found " << classmask << " and no MTVX:" << globalBC;
205 }
206 }
207 }
208 return cntwarnings;
209 };
210
211 auto warningsTRD = genericCTPDigitizer(triggerrecordTRD, classMaskTRD);
212 auto warningsEMCAL = genericCTPDigitizer(triggerRecordEMCALPhys, classMaskEMCAL);
213 auto warningsPHOSCPV = genericCTPDigitizer(triggerrecordPHOSCPV, classMaskPHOSCPV);
214
215 LOG(info) << "createCTPReadout:# of TRD bogus triggers:" << warningsTRD;
216 LOG(info) << "createCTPReadout:# of EMCAL bogus triggers:" << warningsEMCAL;
217 LOG(info) << "createCTPReadout:# of PHOS/CPV bogus triggers:" << warningsPHOSCPV;
218}
219
220void AODProducerWorkflowDPL::collectBCs(const o2::globaltracking::RecoContainer& data,
221 const std::vector<o2::InteractionTimeRecord>& mcRecords,
222 std::map<uint64_t, int>& bcsMap)
223{
224 const auto& primVertices = data.getPrimaryVertices();
225 const auto& fddRecPoints = data.getFDDRecPoints();
226 const auto& ft0RecPoints = data.getFT0RecPoints();
227 const auto& fv0RecPoints = data.getFV0RecPoints();
228 const auto& caloEMCCellsTRGR = data.getEMCALTriggers();
229 const auto& caloPHOSCellsTRGR = data.getPHOSTriggers();
230 const auto& cpvTRGR = data.getCPVTriggers();
231 const auto& ctpDigits = data.getCTPDigits();
232 const auto& zdcBCRecData = data.getZDCBCRecData();
233
234 bcsMap[mStartIR.toLong()] = 1; // store the start of TF
235
236 // collecting non-empty BCs and enumerating them
237 for (auto& rec : mcRecords) {
238 uint64_t globalBC = rec.toLong();
239 bcsMap[globalBC] = 1;
240 }
241
242 for (auto& fddRecPoint : fddRecPoints) {
243 uint64_t globalBC = fddRecPoint.getInteractionRecord().toLong();
244 bcsMap[globalBC] = 1;
245 }
246
247 for (auto& ft0RecPoint : ft0RecPoints) {
248 uint64_t globalBC = ft0RecPoint.getInteractionRecord().toLong();
249 bcsMap[globalBC] = 1;
250 }
251
252 for (auto& fv0RecPoint : fv0RecPoints) {
253 uint64_t globalBC = fv0RecPoint.getInteractionRecord().toLong();
254 bcsMap[globalBC] = 1;
255 }
256
257 for (auto& zdcRecData : zdcBCRecData) {
258 uint64_t globalBC = zdcRecData.ir.toLong();
259 bcsMap[globalBC] = 1;
260 }
261
262 for (auto& vertex : primVertices) {
263 auto& timeStamp = vertex.getTimeStamp();
264 double tsTimeStamp = timeStamp.getTimeStamp() * 1E3; // mus to ns
265 uint64_t globalBC = relativeTime_to_GlobalBC(tsTimeStamp);
266 bcsMap[globalBC] = 1;
267 }
268
269 for (auto& emcaltrg : caloEMCCellsTRGR) {
270 uint64_t globalBC = emcaltrg.getBCData().toLong();
271 bcsMap[globalBC] = 1;
272 }
273
274 for (auto& phostrg : caloPHOSCellsTRGR) {
275 uint64_t globalBC = phostrg.getBCData().toLong();
276 bcsMap[globalBC] = 1;
277 }
278
279 for (auto& cpvtrg : cpvTRGR) {
280 uint64_t globalBC = cpvtrg.getBCData().toLong();
281 bcsMap[globalBC] = 1;
282 }
283
284 for (auto& ctpDigit : ctpDigits) {
285 uint64_t globalBC = ctpDigit.intRecord.toLong();
286 bcsMap[globalBC] = 1;
287 }
288
289 int bcID = 0;
290 for (auto& item : bcsMap) {
291 item.second = bcID;
292 bcID++;
293 }
294}
295
296template <typename TracksCursorType, typename TracksCovCursorType>
297void AODProducerWorkflowDPL::addToTracksTable(TracksCursorType& tracksCursor, TracksCovCursorType& tracksCovCursor,
298 const o2::track::TrackParCov& track, int collisionID, aod::track::TrackTypeEnum type)
299{
300 tracksCursor(collisionID,
301 type,
302 truncateFloatFraction(track.getX(), mTrackX),
303 truncateFloatFraction(track.getAlpha(), mTrackAlpha),
304 track.getY(),
305 track.getZ(),
306 truncateFloatFraction(track.getSnp(), mTrackSnp),
307 truncateFloatFraction(track.getTgl(), mTrackTgl),
308 truncateFloatFraction(track.getQ2Pt(), mTrack1Pt));
309 // trackscov
310 float sY = TMath::Sqrt(track.getSigmaY2()), sZ = TMath::Sqrt(track.getSigmaZ2()), sSnp = TMath::Sqrt(track.getSigmaSnp2()),
311 sTgl = TMath::Sqrt(track.getSigmaTgl2()), sQ2Pt = TMath::Sqrt(track.getSigma1Pt2());
312 tracksCovCursor(truncateFloatFraction(sY, mTrackCovDiag),
313 truncateFloatFraction(sZ, mTrackCovDiag),
314 truncateFloatFraction(sSnp, mTrackCovDiag),
315 truncateFloatFraction(sTgl, mTrackCovDiag),
316 truncateFloatFraction(sQ2Pt, mTrackCovDiag),
317 (Char_t)(128. * track.getSigmaZY() / (sZ * sY)),
318 (Char_t)(128. * track.getSigmaSnpY() / (sSnp * sY)),
319 (Char_t)(128. * track.getSigmaSnpZ() / (sSnp * sZ)),
320 (Char_t)(128. * track.getSigmaTglY() / (sTgl * sY)),
321 (Char_t)(128. * track.getSigmaTglZ() / (sTgl * sZ)),
322 (Char_t)(128. * track.getSigmaTglSnp() / (sTgl * sSnp)),
323 (Char_t)(128. * track.getSigma1PtY() / (sQ2Pt * sY)),
324 (Char_t)(128. * track.getSigma1PtZ() / (sQ2Pt * sZ)),
325 (Char_t)(128. * track.getSigma1PtSnp() / (sQ2Pt * sSnp)),
326 (Char_t)(128. * track.getSigma1PtTgl() / (sQ2Pt * sTgl)));
327}
328
329template <typename TracksExtraCursorType>
330void AODProducerWorkflowDPL::addToTracksExtraTable(TracksExtraCursorType& tracksExtraCursor, TrackExtraInfo& extraInfoHolder)
331{
332 // In case of TPC-only tracks, do not truncate the time error since we encapsulate there a special encoding of
333 // the deltaFwd/Bwd times
334 auto trackTimeRes = extraInfoHolder.trackTimeRes;
335 if (!extraInfoHolder.isTPConly) {
336 trackTimeRes = truncateFloatFraction(trackTimeRes, mTrackTimeError);
337 }
338
339 // extra
340 tracksExtraCursor(truncateFloatFraction(extraInfoHolder.tpcInnerParam, mTrack1Pt),
341 extraInfoHolder.flags,
342 extraInfoHolder.itsClusterSizes,
343 extraInfoHolder.tpcNClsFindable,
344 extraInfoHolder.tpcNClsFindableMinusFound,
345 extraInfoHolder.tpcNClsFindableMinusPID,
346 extraInfoHolder.tpcNClsFindableMinusCrossedRows,
347 extraInfoHolder.tpcNClsShared,
348 extraInfoHolder.trdPattern,
349 truncateFloatFraction(extraInfoHolder.itsChi2NCl, mTrackChi2),
350 truncateFloatFraction(extraInfoHolder.tpcChi2NCl, mTrackChi2),
351 truncateFloatFraction(extraInfoHolder.trdChi2, mTrackChi2),
352 truncateFloatFraction(extraInfoHolder.tofChi2, mTrackChi2),
353 truncateFloatFraction(extraInfoHolder.tpcSignal, mTrackSignal),
354 truncateFloatFraction(extraInfoHolder.trdSignal, mTrackSignal),
355 truncateFloatFraction(extraInfoHolder.length, mTrackSignal),
356 truncateFloatFraction(extraInfoHolder.tofExpMom, mTrack1Pt),
357 truncateFloatFraction(extraInfoHolder.trackEtaEMCAL, mTrackPosEMCAL),
358 truncateFloatFraction(extraInfoHolder.trackPhiEMCAL, mTrackPosEMCAL),
359 truncateFloatFraction(extraInfoHolder.trackTime, mTrackTime),
360 trackTimeRes);
361}
362
363template <typename TracksQACursorType>
364void AODProducerWorkflowDPL::addToTracksQATable(TracksQACursorType& tracksQACursor, TrackQA& trackQAInfoHolder)
365{
366 tracksQACursor(
367 trackQAInfoHolder.trackID,
368 mTrackQCRetainOnlydEdx ? 0.0f : truncateFloatFraction(trackQAInfoHolder.tpcTime0, mTPCTime0),
369 truncateFloatFraction(trackQAInfoHolder.tpcdEdxNorm, mTrackSignal),
370 mTrackQCRetainOnlydEdx ? std::numeric_limits<int16_t>::min() : trackQAInfoHolder.tpcdcaR,
371 mTrackQCRetainOnlydEdx ? std::numeric_limits<int16_t>::min() : trackQAInfoHolder.tpcdcaZ,
372 trackQAInfoHolder.tpcClusterByteMask,
373 trackQAInfoHolder.tpcdEdxMax0R,
374 trackQAInfoHolder.tpcdEdxMax1R,
375 trackQAInfoHolder.tpcdEdxMax2R,
376 trackQAInfoHolder.tpcdEdxMax3R,
377 trackQAInfoHolder.tpcdEdxTot0R,
378 trackQAInfoHolder.tpcdEdxTot1R,
379 trackQAInfoHolder.tpcdEdxTot2R,
380 trackQAInfoHolder.tpcdEdxTot3R,
381 mTrackQCRetainOnlydEdx ? std::numeric_limits<int8_t>::min() : trackQAInfoHolder.dRefContY,
382 mTrackQCRetainOnlydEdx ? std::numeric_limits<int8_t>::min() : trackQAInfoHolder.dRefContZ,
383 mTrackQCRetainOnlydEdx ? std::numeric_limits<int8_t>::min() : trackQAInfoHolder.dRefContSnp,
384 mTrackQCRetainOnlydEdx ? std::numeric_limits<int8_t>::min() : trackQAInfoHolder.dRefContTgl,
385 mTrackQCRetainOnlydEdx ? std::numeric_limits<int8_t>::min() : trackQAInfoHolder.dRefContQ2Pt,
386 mTrackQCRetainOnlydEdx ? std::numeric_limits<int8_t>::min() : trackQAInfoHolder.dRefGloY,
387 mTrackQCRetainOnlydEdx ? std::numeric_limits<int8_t>::min() : trackQAInfoHolder.dRefGloZ,
388 mTrackQCRetainOnlydEdx ? std::numeric_limits<int8_t>::min() : trackQAInfoHolder.dRefGloSnp,
389 mTrackQCRetainOnlydEdx ? std::numeric_limits<int8_t>::min() : trackQAInfoHolder.dRefGloTgl,
390 mTrackQCRetainOnlydEdx ? std::numeric_limits<int8_t>::min() : trackQAInfoHolder.dRefGloQ2Pt,
391 mTrackQCRetainOnlydEdx ? std::numeric_limits<int8_t>::min() : trackQAInfoHolder.dTofdX,
392 mTrackQCRetainOnlydEdx ? std::numeric_limits<int8_t>::min() : trackQAInfoHolder.dTofdZ);
393}
394
395template <typename TRDsExtraCursorType>
396void AODProducerWorkflowDPL::addToTRDsExtra(const o2::globaltracking::RecoContainer& recoData, TRDsExtraCursorType& trdExtraCursor, const GIndex& trkIdx, int trkTableIdx)
397{
398 int q0s[6] = {-1}, q1s[6] = {-1}, q2s[6] = {-1};
399 float q0sCor[6] = {-1}, q1sCor[6] = {-1}, q2sCor[6] = {-1};
400 float ttgls[6] = {-999}, tphis[6] = {-999};
401
402 auto contributorsGID = recoData.getSingleDetectorRefs(trkIdx);
403 if (!contributorsGID[GIndex::Source::TRD].isIndexSet()) { // should be redunant
404 return;
405 }
406 const auto& trk = recoData.getTrack<o2::trd::TrackTRD>(contributorsGID[GIndex::Source::TRD]);
407 o2::track::TrackPar trkC{contributorsGID[GIndex::Source::ITSTPC].isIndexSet() ? recoData.getTPCITSTrack(contributorsGID[GIndex::Source::ITSTPC]).getParamOut() : recoData.getTPCTrack(contributorsGID[GIndex::Source::TPC]).getParamOut()};
408 const auto& trklets = recoData.getTRDTracklets();
409 const auto& ctrklets = recoData.getTRDCalibratedTracklets();
410 for (int iLay{0}; iLay < 6; ++iLay) {
411 q0s[iLay] = q1s[iLay] = q2s[iLay] = -1;
412 q0sCor[iLay] = q1sCor[iLay] = q2sCor[iLay] = -1;
413 tphis[iLay] = ttgls[iLay] = -999;
414 auto trkltId = trk.getTrackletIndex(iLay);
415 if (trkltId < 0) {
416 continue;
417 }
418 const auto& tracklet = trklets[trkltId];
419 if (mTRDNoiseMap->isTrackletFromNoisyMCM(tracklet)) {
420 continue;
421 }
422 // we need to propagate into TRD local system
423 int trkltDet = tracklet.getDetector();
424 int trkltSec = trkltDet / 30;
425 if (trkltSec != o2::math_utils::angle2Sector(trkC.getAlpha())) {
426 if (!trkC.rotate(o2::math_utils::sector2Angle(trkltSec))) {
427 break;
428 }
429 }
430 if (!o2::base::Propagator::Instance()->PropagateToXBxByBz(trkC, ctrklets[trkltId].getX(), o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, mMatCorr)) {
431 break;
432 }
433
434 auto tphi = trkC.getSnp() / std::sqrt((1.f - trkC.getSnp()) * (1.f + trkC.getSnp()));
435 auto trackletLength = std::sqrt(1.f + tphi * tphi + trkC.getTgl() * trkC.getTgl());
436 float cor = mTRDLocalGain->getValue(tracklet.getHCID() / 2, tracklet.getPadCol(), tracklet.getPadRow()) * mTRDGainCalib->getMPVdEdx(tracklet.getDetector()) / o2::trd::constants::MPVDEDXDEFAULT * trackletLength;
437 q0s[iLay] = tracklet.getQ0();
438 q1s[iLay] = tracklet.getQ1();
439 q2s[iLay] = tracklet.getQ2();
440 q0sCor[iLay] = (float)tracklet.getQ0() / cor;
441 q1sCor[iLay] = (float)tracklet.getQ1() / cor;
442 q2sCor[iLay] = (float)tracklet.getQ2() / cor;
443 ttgls[iLay] = trkC.getTgl();
444 tphis[iLay] = tphi;
445
446 // z-row merging, we want to merge only with tracklets from the same trigger record
447 if (trk.getIsCrossingNeighbor(iLay) && trk.getHasNeighbor()) {
448 // find the trigger the tracklet belongs to
449 auto trigsTRD = recoData.getTRDTriggerRecords();
450 size_t trdSelID = -1;
451
452 const auto& trig = trigsTRD[mCurrentTRDTrigID];
453 bool foundTRDTrigger = false;
454 // first check current trigger
455 if (trkltId >= trig.getFirstTracklet() && trkltId < trig.getFirstTracklet() + trig.getNumberOfTracklets()) {
456 trdSelID = mCurrentTRDTrigID;
457 foundTRDTrigger = true;
458 } else {
459 // then check next trigger
460 if (mCurrentTRDTrigID < trigsTRD.size() - 1) {
461 const auto& trig = trigsTRD[mCurrentTRDTrigID + 1];
462 if (trkltId >= trig.getFirstTracklet() && trkltId < trig.getFirstTracklet() + trig.getNumberOfTracklets()) {
463 trdSelID = mCurrentTRDTrigID + 1;
464 foundTRDTrigger = true;
465 }
466 }
467 }
468
469 size_t low = 0, up = trigsTRD.size() - 1;
470
471 // otherwise binary search
472 while (low <= up && !foundTRDTrigger) {
473 trdSelID = low + std::floor((up - low) / 2);
474 const auto& trig = trigsTRD[trdSelID];
475 if (trig.getFirstTracklet() > trkltId) {
476 up = trdSelID - 1;
477 } else {
478 if (trig.getFirstTracklet() + trig.getNumberOfTracklets() <= trkltId) {
479 low = trdSelID + 1;
480 } else {
481 foundTRDTrigger = true;
482 }
483 }
484 }
485 //-------------------
486 mCurrentTRDTrigID = trdSelID;
487 const auto& trigSel = trigsTRD[trdSelID];
488
489 // loop on other tracklets from the same trigger record
490 for (const auto& trklt : trklets.subspan(trigSel.getFirstTracklet(), trigSel.getNumberOfTracklets())) {
491 if (tracklet.getTrackletWord() == trklt.getTrackletWord() || tracklet.getDetector() != trklt.getDetector()) {
492 continue;
493 }
494 if (std::abs(tracklet.getPadCol() - trklt.getPadCol()) <= 1 && std::abs(tracklet.getPadRow() - trklt.getPadRow()) == 1) {
495 cor = mTRDLocalGain->getValue(trklt.getHCID() / 2, trklt.getPadCol(), trklt.getPadRow()) * mTRDGainCalib->getMPVdEdx(tracklet.getDetector()) / o2::trd::constants::MPVDEDXDEFAULT * trackletLength;
496 q0s[iLay] += trklt.getQ0();
497 q1s[iLay] += trklt.getQ1();
498 q2s[iLay] += trklt.getQ2();
499 q0sCor[iLay] += (float)trklt.getQ0() / cor;
500 q1sCor[iLay] += (float)trklt.getQ1() / cor;
501 q2sCor[iLay] += (float)trklt.getQ2() / cor;
502 }
503 }
504 }
505 }
506
507 trdExtraCursor(trkTableIdx, q0s, q1s, q2s, q0sCor, q1sCor, q2sCor, ttgls, tphis);
508}
509
510template <typename mftTracksCursorType, typename AmbigMFTTracksCursorType>
511void AODProducerWorkflowDPL::addToMFTTracksTable(mftTracksCursorType& mftTracksCursor, AmbigMFTTracksCursorType& ambigMFTTracksCursor,
512 GIndex trackID, const o2::globaltracking::RecoContainer& data, int collisionID,
513 std::uint64_t collisionBC, const std::map<uint64_t, int>& bcsMap)
514{
515 // mft tracks
516 int bcSlice[2] = {-1, -1};
517 const auto& track = data.getMFTTrack(trackID);
518 const auto& rof = data.getMFTTracksROFRecords()[mMFTROFs[trackID.getIndex()]];
519 float trackTime = rof.getBCData().differenceInBC(mStartIR) * o2::constants::lhc::LHCBunchSpacingNS + mMFTROFrameHalfLengthNS + mMFTROFBiasNS;
520 float trackTimeRes = mMFTROFrameHalfLengthNS;
521 bool needBCSlice = collisionID < 0;
522 std::uint64_t bcOfTimeRef;
523 if (needBCSlice) {
524 double error = mTimeMarginTrackTime + trackTimeRes;
525 bcOfTimeRef = fillBCSlice(bcSlice, trackTime - error, trackTime + error, bcsMap);
526 } else {
527 bcOfTimeRef = collisionBC - mStartIR.toLong(); // by default (unambiguous) track time is wrt collision BC
528 }
529 trackTime -= bcOfTimeRef * o2::constants::lhc::LHCBunchSpacingNS;
530
531 // the Cellular Automaton track-finding algorithm flag is stored in first of the 4 bits not used for the cluster size
532 uint64_t mftClusterSizesAndTrackFlags = track.getClusterSizes();
533 mftClusterSizesAndTrackFlags |= (track.isCA()) ? (1ULL << (60)) : 0;
534
535 mftTracksCursor(collisionID,
536 track.getX(),
537 track.getY(),
538 truncateFloatFraction(track.getZ(), mTrackX), // for the forward tracks Z has the same role as X in barrel
539 truncateFloatFraction(track.getPhi(), mTrackAlpha),
540 truncateFloatFraction(track.getTanl(), mTrackTgl),
541 truncateFloatFraction(track.getInvQPt(), mTrack1Pt),
542 mftClusterSizesAndTrackFlags,
543 truncateFloatFraction(track.getTrackChi2(), mTrackChi2),
544 truncateFloatFraction(trackTime, mTrackTime),
545 truncateFloatFraction(trackTimeRes, mTrackTimeError));
546 if (needBCSlice) {
547 ambigMFTTracksCursor(mTableTrMFTID, bcSlice);
548 }
549}
550template <typename TracksCursorType, typename TracksCovCursorType, typename TracksExtraCursorType, typename TracksQACursorType, typename TRDsExtraCursor, typename AmbigTracksCursorType,
551 typename MFTTracksCursorType, typename MFTTracksCovCursorType, typename AmbigMFTTracksCursorType,
552 typename FwdTracksCursorType, typename FwdTracksCovCursorType, typename AmbigFwdTracksCursorType, typename FwdTrkClsCursorType>
553void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID,
554 std::uint64_t collisionBC,
555 const o2::dataformats::VtxTrackRef& trackRef,
556 const gsl::span<const GIndex>& GIndices,
558 TracksCursorType& tracksCursor,
559 TracksCovCursorType& tracksCovCursor,
560 TracksExtraCursorType& tracksExtraCursor,
561 TracksQACursorType& tracksQACursor,
562 TRDsExtraCursor& trdsExtraCursor,
563 AmbigTracksCursorType& ambigTracksCursor,
564 MFTTracksCursorType& mftTracksCursor,
565 MFTTracksCovCursorType& mftTracksCovCursor,
566 AmbigMFTTracksCursorType& ambigMFTTracksCursor,
567 FwdTracksCursorType& fwdTracksCursor,
568 FwdTracksCovCursorType& fwdTracksCovCursor,
569 AmbigFwdTracksCursorType& ambigFwdTracksCursor,
570 FwdTrkClsCursorType& fwdTrkClsCursor,
571 const std::map<uint64_t, int>& bcsMap)
572{
573 for (int src = GIndex::NSources; src--;) {
574 if (!GIndex::isTrackSource(src)) {
575 continue;
576 }
577 int start = trackRef.getFirstEntryOfSource(src);
578 int end = start + trackRef.getEntriesOfSource(src);
579 int nToReserve = end - start; // + last index for a given table
580 if (src == GIndex::Source::MFT) {
581 mftTracksCursor.reserve(nToReserve + mftTracksCursor.lastIndex());
583 fwdTracksCursor.reserve(nToReserve + fwdTracksCursor.lastIndex());
584 fwdTracksCovCursor.reserve(nToReserve + fwdTracksCovCursor.lastIndex());
586 mftTracksCovCursor.reserve(nToReserve + mftTracksCovCursor.lastIndex());
587 }
588 } else {
589 tracksCursor.reserve(nToReserve + tracksCursor.lastIndex());
590 tracksCovCursor.reserve(nToReserve + tracksCovCursor.lastIndex());
591 tracksExtraCursor.reserve(nToReserve + tracksExtraCursor.lastIndex());
592 }
593 for (int ti = start; ti < end; ti++) {
594 const auto& trackIndex = GIndices[ti];
595 if (GIndex::includesSource(src, mInputSources)) {
596 if (src == GIndex::Source::MFT) { // MFT tracks are treated separately since they are stored in a different table
597 if (trackIndex.isAmbiguous() && mGIDToTableMFTID.find(trackIndex) != mGIDToTableMFTID.end()) { // was it already stored ?
598 continue;
599 }
600 addToMFTTracksTable(mftTracksCursor, ambigMFTTracksCursor, trackIndex, data, collisionID, collisionBC, bcsMap);
601 mGIDToTableMFTID.emplace(trackIndex, mTableTrMFTID);
602 mTableTrMFTID++;
603 } else if (src == GIndex::Source::MCH || src == GIndex::Source::MFTMCH || src == GIndex::Source::MCHMID) { // FwdTracks tracks are treated separately since they are stored in a different table
604 if (trackIndex.isAmbiguous() && mGIDToTableFwdID.find(trackIndex) != mGIDToTableFwdID.end()) { // was it already stored ?
605 continue;
606 }
607 addToFwdTracksTable(fwdTracksCursor, fwdTracksCovCursor, ambigFwdTracksCursor, mftTracksCovCursor, trackIndex, data, collisionID, collisionBC, bcsMap);
608 mGIDToTableFwdID.emplace(trackIndex, mTableTrFwdID);
609 addClustersToFwdTrkClsTable(data, fwdTrkClsCursor, trackIndex, mTableTrFwdID);
610 mTableTrFwdID++;
611 } else {
612 // barrel track: normal tracks table
613 if (trackIndex.isAmbiguous() && mGIDToTableID.find(trackIndex) != mGIDToTableID.end()) { // was it already stored ?
614 continue;
615 }
616
617 float weight = 0;
618 static std::uniform_real_distribution<> distr(0., 1.);
619 bool writeQAData = o2::math_utils::Tsallis::downsampleTsallisCharged(data.getTrackParam(trackIndex).getPt(), mTrackQCFraction, mSqrtS, weight, distr(mGenerator)) || ((src != GIndex::TPC || mGIDUsedBySVtx.find(trackIndex) != mGIDUsedBySVtx.end() || mGIDUsedByStr.find(trackIndex) != mGIDUsedByStr.end()) && mTrackQCKeepGlobalTracks);
620 auto extraInfoHolder = processBarrelTrack(collisionID, collisionBC, trackIndex, data, bcsMap);
621
622 if (writeQAData) {
623 auto trackQAInfoHolder = processBarrelTrackQA(collisionID, collisionBC, trackIndex, data, bcsMap);
624 if (std::bitset<8>(trackQAInfoHolder.tpcClusterByteMask).count() >= mTrackQCNTrCut) {
625 trackQAInfoHolder.trackID = mTableTrID;
626 // LOGP(info, "orig time0 in bc: {} diffBCRef: {}, ttime: {} -> {}", trackQAInfoHolder.tpcTime0*8, extraInfoHolder.diffBCRef, extraInfoHolder.trackTime, (trackQAInfoHolder.tpcTime0 * 8 - extraInfoHolder.diffBCRef) * o2::constants::lhc::LHCBunchSpacingNS - extraInfoHolder.trackTime);
627 trackQAInfoHolder.tpcTime0 = (trackQAInfoHolder.tpcTime0 * 8 - extraInfoHolder.diffBCRef) * o2::constants::lhc::LHCBunchSpacingNS - extraInfoHolder.trackTime;
628 // difference between TPC track time0 and stored track nominal time in ns instead of TF start
629 addToTracksQATable(tracksQACursor, trackQAInfoHolder);
630 } else {
631 writeQAData = false;
632 }
633 }
634
635 // include specific selection of tpc standalone tracks if thinning is active
636 if (mThinTracks && extraInfoHolder.isTPConly && !writeQAData) { // if trackQA is written then no check has to be done
637 auto trk = data.getTPCTrack(trackIndex);
638 if (trk.getNClusters() >= mTrackQCNCls && trk.getPt() >= mTrackQCPt) {
639 o2::dataformats::DCA dcaInfo{999.f, 999.f, 999.f, 999.f, 999.f};
640 o2::dataformats::VertexBase v = mVtx.getMeanVertex(collisionID < 0 ? 0.f : data.getPrimaryVertex(collisionID).getZ());
641 if (o2::base::Propagator::Instance()->propagateToDCABxByBz(v, trk, 2., mMatCorr, &dcaInfo) && std::abs(dcaInfo.getY()) < mTrackQCDCAxy) {
642 writeQAData = true; // just setting this to not thin the track
643 }
644 }
645 }
646
647 // Skip thinning if not enabled or track is not tpc standalone or assoc. to a V0 or qa'ed
648 if (mThinTracks && src == GIndex::Source::TPC && mGIDUsedBySVtx.find(trackIndex) == mGIDUsedBySVtx.end() && mGIDUsedByStr.find(trackIndex) == mGIDUsedByStr.end() && !writeQAData) {
649 mGIDToTableID.emplace(trackIndex, -1); // pretend skipped tracks are stored; this is safe since they are are not written to disk and -1 indicates to all users to not use this track
650 continue;
651 }
652
653 if (!extraInfoHolder.isTPConly && extraInfoHolder.trackTimeRes < 0.f) { // failed or rejected?
654 LOG(warning) << "Barrel track " << trackIndex << " has no time set, rejection is not expected : time=" << extraInfoHolder.trackTime
655 << " timeErr=" << extraInfoHolder.trackTimeRes << " BCSlice: " << extraInfoHolder.bcSlice[0] << ":" << extraInfoHolder.bcSlice[1];
656 continue;
657 }
658 const auto& trOrig = data.getTrackParam(trackIndex);
659 bool isProp = false;
660 if (mPropTracks && trOrig.getX() < mMaxPropXiu &&
661 mGIDUsedBySVtx.find(trackIndex) == mGIDUsedBySVtx.end() &&
662 mGIDUsedByStr.find(trackIndex) == mGIDUsedByStr.end()) { // Do not propagate track assoc. to V0s and str. tracking
663 auto trackPar(trOrig);
664 isProp = propagateTrackToPV(trackPar, data, collisionID);
665 if (isProp) {
666 addToTracksTable(tracksCursor, tracksCovCursor, trackPar, collisionID, aod::track::Track);
667 }
668 }
669 if (!isProp) {
670 addToTracksTable(tracksCursor, tracksCovCursor, trOrig, collisionID, aod::track::TrackIU);
671 }
672 addToTracksExtraTable(tracksExtraCursor, extraInfoHolder);
673 if (mEnableTRDextra && trackIndex.includesDet(GIndex::Source::TRD)) {
674 addToTRDsExtra(data, trdsExtraCursor, trackIndex, mTableTrID);
675 }
676 // collecting table indices of barrel tracks for V0s table
677 if (extraInfoHolder.bcSlice[0] >= 0 && collisionID < 0) {
678 ambigTracksCursor(mTableTrID, extraInfoHolder.bcSlice);
679 }
680 mGIDToTableID.emplace(trackIndex, mTableTrID);
681 mTableTrID++;
682 }
683 }
684 }
685 }
686 if (collisionID < 0) {
687 return;
688 }
690 auto sTracks = data.getStrangeTracks();
691 tracksCursor.reserve(mVertexStrLUT[collisionID + 1] + tracksCursor.lastIndex());
692 tracksCovCursor.reserve(mVertexStrLUT[collisionID + 1] + tracksCovCursor.lastIndex());
693 tracksExtraCursor.reserve(mVertexStrLUT[collisionID + 1] + tracksExtraCursor.lastIndex());
694 for (int iS{mVertexStrLUT[collisionID]}; iS < mVertexStrLUT[collisionID + 1]; ++iS) {
695 auto& collStrTrk = mCollisionStrTrk[iS];
696 auto& sTrk = sTracks[collStrTrk.second];
697 TrackExtraInfo extraInfo;
698 extraInfo.itsChi2NCl = sTrk.mTopoChi2; // TODO: this is the total chi2 of adding the ITS clusters, the topology chi2 meaning might change in the future
699 extraInfo.itsClusterSizes = sTrk.getClusterSizes();
700 addToTracksTable(tracksCursor, tracksCovCursor, sTrk.mMother, collisionID, aod::track::StrangeTrack);
701 addToTracksExtraTable(tracksExtraCursor, extraInfo);
702 mStrTrkIndices[collStrTrk.second] = mTableTrID;
703 mTableTrID++;
704 }
705}
706
707void AODProducerWorkflowDPL::fillIndexTablesPerCollision(const o2::dataformats::VtxTrackRef& trackRef, const gsl::span<const GIndex>& GIndices, const o2::globaltracking::RecoContainer& data)
708{
709 const auto& mchmidMatches = data.getMCHMIDMatches();
710
712 int start = trackRef.getFirstEntryOfSource(src);
713 int end = start + trackRef.getEntriesOfSource(src);
714 for (int ti = start; ti < end; ti++) {
715 auto& trackIndex = GIndices[ti];
716 if (GIndex::includesSource(src, mInputSources)) {
717 if (src == GIndex::Source::MFT) {
718 if (trackIndex.isAmbiguous() && mGIDToTableMFTID.find(trackIndex) != mGIDToTableMFTID.end()) {
719 continue;
720 }
721 mGIDToTableMFTID.emplace(trackIndex, mIndexMFTID);
722 mIndexTableMFT[trackIndex.getIndex()] = mIndexMFTID;
723 mIndexMFTID++;
725 if (trackIndex.isAmbiguous() && mGIDToTableFwdID.find(trackIndex) != mGIDToTableFwdID.end()) {
726 continue;
727 }
728 mGIDToTableFwdID.emplace(trackIndex, mIndexFwdID);
729 if (src == GIndex::Source::MCH) {
730 mIndexTableFwd[trackIndex.getIndex()] = mIndexFwdID;
731 } else if (src == GIndex::Source::MCHMID) {
732 const auto& mchmidMatch = mchmidMatches[trackIndex.getIndex()];
733 const auto mchTrackID = mchmidMatch.getMCHRef().getIndex();
734 mIndexTableFwd[mchTrackID] = mIndexFwdID;
735 }
736 mIndexFwdID++;
737 }
738 }
739 }
740 }
741}
742
743template <typename FwdTracksCursorType, typename FwdTracksCovCursorType, typename AmbigFwdTracksCursorType, typename mftTracksCovCursorType>
744void AODProducerWorkflowDPL::addToFwdTracksTable(FwdTracksCursorType& fwdTracksCursor, FwdTracksCovCursorType& fwdTracksCovCursor,
745 AmbigFwdTracksCursorType& ambigFwdTracksCursor, mftTracksCovCursorType& mftTracksCovCursor, GIndex trackID,
746 const o2::globaltracking::RecoContainer& data, int collisionID, std::uint64_t collisionBC,
747 const std::map<uint64_t, int>& bcsMap)
748{
749 const auto& mchTracks = data.getMCHTracks();
750 const auto& midTracks = data.getMIDTracks();
751 const auto& mchmidMatches = data.getMCHMIDMatches();
752 const auto& mchClusters = data.getMCHTrackClusters();
753
754 FwdTrackInfo fwdInfo;
755 FwdTrackCovInfo fwdCovInfo;
756 int bcSlice[2] = {-1, -1};
757
758 // helper lambda for mch bitmap -- common for global and standalone tracks
759 auto getMCHBitMap = [&](int mchTrackID) {
760 if (mchTrackID != -1) { // check matching just in case
761 const auto& mchTrack = mchTracks[mchTrackID];
762 int first = mchTrack.getFirstClusterIdx();
763 int last = mchTrack.getLastClusterIdx();
764 for (int i = first; i <= last; i++) { // check chamberIds of all clusters
765 const auto& cluster = mchClusters[i];
766 int chamberId = cluster.getChamberId();
767 fwdInfo.mchBitMap |= 1 << chamberId;
768 }
769 }
770 };
771
772 auto getMIDBitMapBoards = [&](int midTrackID) {
773 if (midTrackID != -1) { // check matching just in case
774 const auto& midTrack = midTracks[midTrackID];
775 fwdInfo.midBitMap = midTrack.getHitMap();
776 fwdInfo.midBoards = midTrack.getEfficiencyWord();
777 }
778 };
779
780 auto extrapMCHTrack = [&](int mchTrackID) {
781 const auto& track = mchTracks[mchTrackID];
782
783 // mch standalone tracks extrapolated to vertex
784 // compute 3 sets of tracks parameters :
785 // - at vertex
786 // - at DCA
787 // - at the end of the absorber
788 // extrapolate to vertex
789 float vx = 0, vy = 0, vz = 0;
790 if (collisionID >= 0) {
791 const auto& v = data.getPrimaryVertex(collisionID);
792 vx = v.getX();
793 vy = v.getY();
794 vz = v.getZ();
795 }
796
797 o2::mch::TrackParam trackParamAtVertex(track.getZ(), track.getParameters(), track.getCovariances());
798 if (mPropMuons) {
799 double errVtx{0.0}; // FIXME: get errors associated with vertex if available
800 double errVty{0.0};
801 if (!o2::mch::TrackExtrap::extrapToVertex(trackParamAtVertex, vx, vy, vz, errVtx, errVty)) {
802 return false;
803 }
804 }
805
806 // extrapolate to DCA
807 o2::mch::TrackParam trackParamAtDCA(track.getZ(), track.getParameters());
808 if (!o2::mch::TrackExtrap::extrapToVertexWithoutBranson(trackParamAtDCA, vz)) {
809 return false;
810 }
811
812 // extrapolate to the end of the absorber
813 o2::mch::TrackParam trackParamAtRAbs(track.getZ(), track.getParameters());
814 if (!o2::mch::TrackExtrap::extrapToZ(trackParamAtRAbs, -505.)) { // FIXME: replace hardcoded 505
815 return false;
816 }
817
818 double dcaX = trackParamAtDCA.getNonBendingCoor() - vx;
819 double dcaY = trackParamAtDCA.getBendingCoor() - vy;
820 double dca = std::sqrt(dcaX * dcaX + dcaY * dcaY);
821
822 double xAbs = trackParamAtRAbs.getNonBendingCoor();
823 double yAbs = trackParamAtRAbs.getBendingCoor();
824
825 double dpdca = track.getP() * dca;
826 double dchi2 = track.getChi2OverNDF();
827
828 auto fwdmuon = mMatching.MCHtoFwd(trackParamAtVertex);
829
830 fwdInfo.x = fwdmuon.getX();
831 fwdInfo.y = fwdmuon.getY();
832 fwdInfo.z = fwdmuon.getZ();
833 fwdInfo.phi = fwdmuon.getPhi();
834 fwdInfo.tanl = fwdmuon.getTgl();
835 fwdInfo.invqpt = fwdmuon.getInvQPt();
836 fwdInfo.rabs = std::sqrt(xAbs * xAbs + yAbs * yAbs);
837 fwdInfo.chi2 = dchi2;
838 fwdInfo.pdca = dpdca;
839 fwdInfo.nClusters = track.getNClusters();
840
841 fwdCovInfo.sigX = TMath::Sqrt(fwdmuon.getCovariances()(0, 0));
842 fwdCovInfo.sigY = TMath::Sqrt(fwdmuon.getCovariances()(1, 1));
843 fwdCovInfo.sigPhi = TMath::Sqrt(fwdmuon.getCovariances()(2, 2));
844 fwdCovInfo.sigTgl = TMath::Sqrt(fwdmuon.getCovariances()(3, 3));
845 fwdCovInfo.sig1Pt = TMath::Sqrt(fwdmuon.getCovariances()(4, 4));
846 fwdCovInfo.rhoXY = (Char_t)(128. * fwdmuon.getCovariances()(0, 1) / (fwdCovInfo.sigX * fwdCovInfo.sigY));
847 fwdCovInfo.rhoPhiX = (Char_t)(128. * fwdmuon.getCovariances()(0, 2) / (fwdCovInfo.sigPhi * fwdCovInfo.sigX));
848 fwdCovInfo.rhoPhiY = (Char_t)(128. * fwdmuon.getCovariances()(1, 2) / (fwdCovInfo.sigPhi * fwdCovInfo.sigY));
849 fwdCovInfo.rhoTglX = (Char_t)(128. * fwdmuon.getCovariances()(0, 3) / (fwdCovInfo.sigTgl * fwdCovInfo.sigX));
850 fwdCovInfo.rhoTglY = (Char_t)(128. * fwdmuon.getCovariances()(1, 3) / (fwdCovInfo.sigTgl * fwdCovInfo.sigY));
851 fwdCovInfo.rhoTglPhi = (Char_t)(128. * fwdmuon.getCovariances()(2, 3) / (fwdCovInfo.sigTgl * fwdCovInfo.sigPhi));
852 fwdCovInfo.rho1PtX = (Char_t)(128. * fwdmuon.getCovariances()(0, 4) / (fwdCovInfo.sig1Pt * fwdCovInfo.sigX));
853 fwdCovInfo.rho1PtY = (Char_t)(128. * fwdmuon.getCovariances()(1, 4) / (fwdCovInfo.sig1Pt * fwdCovInfo.sigY));
854 fwdCovInfo.rho1PtPhi = (Char_t)(128. * fwdmuon.getCovariances()(2, 4) / (fwdCovInfo.sig1Pt * fwdCovInfo.sigPhi));
855 fwdCovInfo.rho1PtTgl = (Char_t)(128. * fwdmuon.getCovariances()(3, 4) / (fwdCovInfo.sig1Pt * fwdCovInfo.sigTgl));
856
857 return true;
858 };
859
860 if (trackID.getSource() == GIndex::MCH) { // This is an MCH track
861 int mchTrackID = trackID.getIndex();
862 getMCHBitMap(mchTrackID);
863 if (!extrapMCHTrack(mchTrackID)) {
864 LOGF(warn, "Unable to extrapolate MCH track with ID %d! Dummy parameters will be used", mchTrackID);
865 }
866 fwdInfo.trackTypeId = o2::aod::fwdtrack::MCHStandaloneTrack;
867 const auto& rof = data.getMCHTracksROFRecords()[mMCHROFs[mchTrackID]];
868 auto time = rof.getTimeMUS(mStartIR).first;
869 fwdInfo.trackTime = time.getTimeStamp() * 1.e3;
870 fwdInfo.trackTimeRes = time.getTimeStampError() * 1.e3;
871 } else if (trackID.getSource() == GIndex::MCHMID) { // This is an MCH-MID track
872 fwdInfo.trackTypeId = o2::aod::fwdtrack::MuonStandaloneTrack;
873 auto mchmidMatch = mchmidMatches[trackID.getIndex()];
874 auto mchTrackID = mchmidMatch.getMCHRef().getIndex();
875 if (!extrapMCHTrack(mchTrackID)) {
876 LOGF(warn, "Unable to extrapolate MCH track with ID %d! Dummy parameters will be used", mchTrackID);
877 }
878 auto midTrackID = mchmidMatch.getMIDRef().getIndex();
879 fwdInfo.chi2matchmchmid = mchmidMatch.getMatchChi2OverNDF();
880 getMCHBitMap(mchTrackID);
881 getMIDBitMapBoards(midTrackID);
882 auto time = mchmidMatch.getTimeMUS(mStartIR).first;
883 fwdInfo.trackTime = time.getTimeStamp() * 1.e3;
884 fwdInfo.trackTimeRes = time.getTimeStampError() * 1.e3;
885 } else { // This is a GlobalMuonTrack or a GlobalForwardTrack
886 const auto& track = data.getGlobalFwdTrack(trackID);
887 const auto& mftTracks = data.getMFTTracks();
888 const auto& mfttrack = mftTracks[track.getMFTTrackID()];
889 if (!extrapMCHTrack(track.getMCHTrackID())) {
890 LOGF(warn, "Unable to extrapolate MCH track with ID %d! Dummy parameters will be used", track.getMCHTrackID());
891 }
892 fwdInfo.x = track.getX();
893 fwdInfo.y = track.getY();
894 fwdInfo.z = track.getZ();
895 fwdInfo.phi = track.getPhi();
896 fwdInfo.tanl = track.getTanl();
897 fwdInfo.invqpt = track.getInvQPt();
898 fwdInfo.chi2 = track.getTrackChi2();
899 // fwdInfo.nClusters = track.getNumberOfPoints();
900 fwdInfo.chi2matchmchmid = track.getMIDMatchingChi2();
901 fwdInfo.chi2matchmchmft = track.getMFTMCHMatchingChi2();
902 fwdInfo.matchscoremchmft = track.getMFTMCHMatchingScore();
903 fwdInfo.matchmfttrackid = mIndexTableMFT[track.getMFTTrackID()];
904 fwdInfo.matchmchtrackid = mIndexTableFwd[track.getMCHTrackID()];
905 fwdInfo.trackTime = track.getTimeMUS().getTimeStamp() * 1.e3;
906 fwdInfo.trackTimeRes = track.getTimeMUS().getTimeStampError() * 1.e3;
907
908 getMCHBitMap(track.getMCHTrackID());
909 getMIDBitMapBoards(track.getMIDTrackID());
910
911 fwdCovInfo.sigX = TMath::Sqrt(track.getCovariances()(0, 0));
912 fwdCovInfo.sigY = TMath::Sqrt(track.getCovariances()(1, 1));
913 fwdCovInfo.sigPhi = TMath::Sqrt(track.getCovariances()(2, 2));
914 fwdCovInfo.sigTgl = TMath::Sqrt(track.getCovariances()(3, 3));
915 fwdCovInfo.sig1Pt = TMath::Sqrt(track.getCovariances()(4, 4));
916 fwdCovInfo.rhoXY = (Char_t)(128. * track.getCovariances()(0, 1) / (fwdCovInfo.sigX * fwdCovInfo.sigY));
917 fwdCovInfo.rhoPhiX = (Char_t)(128. * track.getCovariances()(0, 2) / (fwdCovInfo.sigPhi * fwdCovInfo.sigX));
918 fwdCovInfo.rhoPhiY = (Char_t)(128. * track.getCovariances()(1, 2) / (fwdCovInfo.sigPhi * fwdCovInfo.sigY));
919 fwdCovInfo.rhoTglX = (Char_t)(128. * track.getCovariances()(0, 3) / (fwdCovInfo.sigTgl * fwdCovInfo.sigX));
920 fwdCovInfo.rhoTglY = (Char_t)(128. * track.getCovariances()(1, 3) / (fwdCovInfo.sigTgl * fwdCovInfo.sigY));
921 fwdCovInfo.rhoTglPhi = (Char_t)(128. * track.getCovariances()(2, 3) / (fwdCovInfo.sigTgl * fwdCovInfo.sigPhi));
922 fwdCovInfo.rho1PtX = (Char_t)(128. * track.getCovariances()(0, 4) / (fwdCovInfo.sig1Pt * fwdCovInfo.sigX));
923 fwdCovInfo.rho1PtY = (Char_t)(128. * track.getCovariances()(1, 4) / (fwdCovInfo.sig1Pt * fwdCovInfo.sigY));
924 fwdCovInfo.rho1PtPhi = (Char_t)(128. * track.getCovariances()(2, 4) / (fwdCovInfo.sig1Pt * fwdCovInfo.sigPhi));
925 fwdCovInfo.rho1PtTgl = (Char_t)(128. * track.getCovariances()(3, 4) / (fwdCovInfo.sig1Pt * fwdCovInfo.sigTgl));
926
927 fwdInfo.trackTypeId = (fwdInfo.chi2matchmchmid >= 0) ? o2::aod::fwdtrack::GlobalMuonTrack : o2::aod::fwdtrack::GlobalForwardTrack;
928
929 float sX = TMath::Sqrt(mfttrack.getSigma2X()), sY = TMath::Sqrt(mfttrack.getSigma2Y()), sPhi = TMath::Sqrt(mfttrack.getSigma2Phi()),
930 sTgl = TMath::Sqrt(mfttrack.getSigma2Tanl()), sQ2Pt = TMath::Sqrt(mfttrack.getSigma2InvQPt());
931
932 mftTracksCovCursor(fwdInfo.matchmfttrackid,
933 truncateFloatFraction(sX, mTrackCovDiag),
934 truncateFloatFraction(sY, mTrackCovDiag),
935 truncateFloatFraction(sPhi, mTrackCovDiag),
936 truncateFloatFraction(sTgl, mTrackCovDiag),
937 truncateFloatFraction(sQ2Pt, mTrackCovDiag),
938 (Char_t)(128. * mfttrack.getCovariances()(0, 1) / (sX * sY)),
939 (Char_t)(128. * mfttrack.getCovariances()(0, 2) / (sPhi * sX)),
940 (Char_t)(128. * mfttrack.getCovariances()(1, 2) / (sPhi * sY)),
941 (Char_t)(128. * mfttrack.getCovariances()(0, 3) / (sTgl * sX)),
942 (Char_t)(128. * mfttrack.getCovariances()(1, 3) / (sTgl * sY)),
943 (Char_t)(128. * mfttrack.getCovariances()(2, 3) / (sTgl * sPhi)),
944 (Char_t)(128. * mfttrack.getCovariances()(0, 4) / (sQ2Pt * sX)),
945 (Char_t)(128. * mfttrack.getCovariances()(1, 4) / (sQ2Pt * sY)),
946 (Char_t)(128. * mfttrack.getCovariances()(2, 4) / (sQ2Pt * sPhi)),
947 (Char_t)(128. * mfttrack.getCovariances()(3, 4) / (sQ2Pt * sTgl)));
948 }
949
950 std::uint64_t bcOfTimeRef;
951 bool needBCSlice = collisionID < 0;
952 if (needBCSlice) { // need to store BC slice
953 float err = mTimeMarginTrackTime + fwdInfo.trackTimeRes;
954 bcOfTimeRef = fillBCSlice(bcSlice, fwdInfo.trackTime - err, fwdInfo.trackTime + err, bcsMap);
955 } else {
956 bcOfTimeRef = collisionBC - mStartIR.toLong(); // by default track time is wrt collision BC (unless no collision assigned)
957 }
958 fwdInfo.trackTime -= bcOfTimeRef * o2::constants::lhc::LHCBunchSpacingNS;
959
960 fwdTracksCursor(collisionID,
961 fwdInfo.trackTypeId,
962 fwdInfo.x,
963 fwdInfo.y,
964 truncateFloatFraction(fwdInfo.z, mTrackX), // for the forward tracks Z has the same role as X in the barrel
965 truncateFloatFraction(fwdInfo.phi, mTrackAlpha),
966 truncateFloatFraction(fwdInfo.tanl, mTrackTgl),
967 truncateFloatFraction(fwdInfo.invqpt, mTrack1Pt),
968 fwdInfo.nClusters,
969 truncateFloatFraction(fwdInfo.pdca, mTrackX),
970 truncateFloatFraction(fwdInfo.rabs, mTrackX),
971 truncateFloatFraction(fwdInfo.chi2, mTrackChi2),
972 truncateFloatFraction(fwdInfo.chi2matchmchmid, mTrackChi2),
973 truncateFloatFraction(fwdInfo.chi2matchmchmft, mTrackChi2),
974 truncateFloatFraction(fwdInfo.matchscoremchmft, mTrackChi2),
975 fwdInfo.matchmfttrackid,
976 fwdInfo.matchmchtrackid,
977 fwdInfo.mchBitMap,
978 fwdInfo.midBitMap,
979 fwdInfo.midBoards,
980 truncateFloatFraction(fwdInfo.trackTime, mTrackTime),
981 truncateFloatFraction(fwdInfo.trackTimeRes, mTrackTimeError));
982
983 fwdTracksCovCursor(truncateFloatFraction(fwdCovInfo.sigX, mTrackCovDiag),
984 truncateFloatFraction(fwdCovInfo.sigY, mTrackCovDiag),
985 truncateFloatFraction(fwdCovInfo.sigPhi, mTrackCovDiag),
986 truncateFloatFraction(fwdCovInfo.sigTgl, mTrackCovDiag),
987 truncateFloatFraction(fwdCovInfo.sig1Pt, mTrackCovDiag),
988 fwdCovInfo.rhoXY,
989 fwdCovInfo.rhoPhiX,
990 fwdCovInfo.rhoPhiY,
991 fwdCovInfo.rhoTglX,
992 fwdCovInfo.rhoTglY,
993 fwdCovInfo.rhoTglPhi,
994 fwdCovInfo.rho1PtX,
995 fwdCovInfo.rho1PtY,
996 fwdCovInfo.rho1PtPhi,
997 fwdCovInfo.rho1PtTgl);
998
999 if (needBCSlice) {
1000 ambigFwdTracksCursor(mTableTrFwdID, bcSlice);
1001 }
1002}
1003
1004//------------------------------------------------------------------
1005void AODProducerWorkflowDPL::updateMCHeader(MCCollisionCursor& collisionCursor,
1006 XSectionCursor& xSectionCursor,
1007 PdfInfoCursor& pdfInfoCursor,
1008 HeavyIonCursor& heavyIonCursor,
1009 const MCEventHeader& header,
1010 int collisionID,
1011 int bcID,
1012 float time,
1013 short generatorID,
1014 int sourceID)
1015{
1020
1021 auto genID = updateMCCollisions(collisionCursor,
1022 bcID,
1023 time,
1024 header,
1025 generatorID,
1026 sourceID,
1027 mCollisionPosition);
1028 mXSectionUpdate = (updateHepMCXSection(xSectionCursor, //
1029 collisionID, //
1030 genID, //
1031 header, //
1032 mXSectionUpdate)
1033 ? HepMCUpdate::always
1034 : HepMCUpdate::never);
1035 mPdfInfoUpdate = (updateHepMCPdfInfo(pdfInfoCursor, //
1036 collisionID, //
1037 genID, //
1038 header, //
1039 mPdfInfoUpdate)
1040 ? HepMCUpdate::always
1041 : HepMCUpdate::never);
1042 mHeavyIonUpdate = (updateHepMCHeavyIon(heavyIonCursor, //
1043 collisionID, //
1044 genID, //
1045 header,
1046 mHeavyIonUpdate)
1047 ? HepMCUpdate::always
1048 : HepMCUpdate::never);
1049}
1050
1051void dimensionMCKeepStore(std::vector<std::vector<std::unordered_map<int, int>>>& store, int Nsources, int NEvents)
1052{
1053 store.resize(Nsources);
1054 for (int s = 0; s < Nsources; ++s) {
1055 store[s].resize(NEvents);
1056 }
1057}
1058
1059void clearMCKeepStore(std::vector<std::vector<std::unordered_map<int, int>>>& store)
1060{
1061 for (auto s = 0U; s < store.size(); ++s) {
1062 for (auto e = 0U; e < store[s].size(); ++e) {
1063 store[s][e].clear();
1064 }
1065 }
1066}
1067
1068// helper function to add a particle/track to the MC keep store
1069void keepMCParticle(std::vector<std::vector<std::unordered_map<int, int>>>& store, int source, int event, int track, int value = 1, bool useSigFilt = false)
1070{
1071 if (track < 0) {
1072 LOG(warn) << "trackID is smaller than 0. Neglecting";
1073 return;
1074 }
1075 if (useSigFilt && source == 0) {
1076 store[source][event][track] = -1;
1077 } else {
1078 store[source][event][track] = value;
1079 }
1080}
1081
1082void AODProducerWorkflowDPL::fillMCParticlesTable(o2::steer::MCKinematicsReader& mcReader,
1083 MCParticlesCursor& mcParticlesCursor,
1084 const gsl::span<const o2::dataformats::VtxTrackRef>& primVer2TRefs,
1085 const gsl::span<const GIndex>& GIndices,
1087 const std::vector<std::vector<int>>& mcColToEvSrc)
1088{
1089 int NSources = 0;
1090 int NEvents = 0;
1091 for (auto& p : mcColToEvSrc) {
1092 NSources = std::max(p[1], NSources);
1093 NEvents = std::max(p[2], NEvents);
1094 }
1095 NSources++; // 0 - indexed
1096 NEvents++;
1097 LOG(info) << " number of events " << NEvents;
1098 LOG(info) << " number of sources " << NSources;
1099 dimensionMCKeepStore(mToStore, NSources, NEvents);
1100
1101 std::vector<int> particleIDsToKeep;
1102
1103 auto markMCTrackForSrc = [&](std::array<GID, GID::NSources>& contributorsGID, uint8_t src) {
1104 auto mcLabel = data.getTrackMCLabel(contributorsGID[src]);
1105 if (!mcLabel.isValid()) {
1106 return;
1107 }
1108 keepMCParticle(mToStore, mcLabel.getSourceID(), mcLabel.getEventID(), mcLabel.getTrackID(), 1, mUseSigFiltMC);
1109 };
1110
1111 // mark reconstructed MC particles to store them into the table
1112 for (auto& trackRef : primVer2TRefs) {
1113 for (int src = GIndex::NSources; src--;) {
1114 int start = trackRef.getFirstEntryOfSource(src);
1115 int end = start + trackRef.getEntriesOfSource(src);
1116 for (int ti = start; ti < end; ti++) {
1117 auto& trackIndex = GIndices[ti];
1118 if (GIndex::includesSource(src, mInputSources)) {
1119 auto mcTruth = data.getTrackMCLabel(trackIndex);
1120 if (!mcTruth.isValid()) {
1121 continue;
1122 }
1123 keepMCParticle(mToStore, mcTruth.getSourceID(), mcTruth.getEventID(), mcTruth.getTrackID(), 1, mUseSigFiltMC);
1124 // treating contributors of global tracks
1125 auto contributorsGID = data.getSingleDetectorRefs(trackIndex);
1126 if (contributorsGID[GIndex::Source::TPC].isIndexSet()) {
1127 markMCTrackForSrc(contributorsGID, GIndex::Source::TPC);
1128 }
1129 if (contributorsGID[GIndex::Source::ITS].isIndexSet()) {
1130 markMCTrackForSrc(contributorsGID, GIndex::Source::ITS);
1131 }
1132 if (contributorsGID[GIndex::Source::TOF].isIndexSet()) {
1133 const auto& labelsTOF = data.getTOFClustersMCLabels()->getLabels(contributorsGID[GIndex::Source::TOF]);
1134 for (auto& mcLabel : labelsTOF) {
1135 if (!mcLabel.isValid()) {
1136 continue;
1137 }
1138 keepMCParticle(mToStore, mcLabel.getSourceID(), mcLabel.getEventID(), mcLabel.getTrackID(), 1, mUseSigFiltMC);
1139 }
1140 }
1141 }
1142 }
1143 }
1144 }
1145 // mark calorimeter signals as reconstructed particles
1146 if (mInputSources[GIndex::EMC]) {
1147 auto& mcCaloEMCCellLabels = data.getEMCALCellsMCLabels()->getTruthArray();
1148 for (auto& mcTruth : mcCaloEMCCellLabels) {
1149 if (!mcTruth.isValid()) {
1150 continue;
1151 }
1152 keepMCParticle(mToStore, mcTruth.getSourceID(), mcTruth.getEventID(), mcTruth.getTrackID(), 1, mUseSigFiltMC);
1153 }
1154 }
1155 if (mInputSources[GIndex::PHS]) {
1156 auto& mcCaloPHOSCellLabels = data.getPHOSCellsMCLabels()->getTruthArray();
1157 for (auto& mcTruth : mcCaloPHOSCellLabels) {
1158 if (!mcTruth.isValid()) {
1159 continue;
1160 }
1161 keepMCParticle(mToStore, mcTruth.getSourceID(), mcTruth.getEventID(), mcTruth.getTrackID(), 1, mUseSigFiltMC);
1162 }
1163 }
1164 using namespace aodmchelpers;
1165 using MCTrackNavigator = o2::mcutils::MCTrackNavigator;
1166
1167 size_t offset = 0;
1168 for (auto& colInfo : mcColToEvSrc) { // loop over "<eventID, sourceID> <-> combined MC col. ID" key pairs
1169 int event = colInfo[2];
1170 int source = colInfo[1];
1171 int mcColId = colInfo[0];
1172 std::vector<MCTrack> const& mcParticles = mcReader.getTracks(source, event);
1173 LOG(debug) << "Event=" << event << " source=" << source << " collision=" << mcColId;
1174 auto& preselect = mToStore[source][event];
1175
1176 offset = updateParticles(mcParticlesCursor,
1177 mcColId,
1178 mcParticles,
1179 preselect,
1180 offset,
1181 mRecoOnly,
1182 source == 0, // background
1183 mMcParticleW,
1184 mMcParticleMom,
1185 mMcParticlePos,
1186 mUseSigFiltMC);
1187
1189 }
1190}
1191
1192template <typename MCTrackLabelCursorType, typename MCMFTTrackLabelCursorType, typename MCFwdTrackLabelCursorType>
1193void AODProducerWorkflowDPL::fillMCTrackLabelsTable(MCTrackLabelCursorType& mcTrackLabelCursor,
1194 MCMFTTrackLabelCursorType& mcMFTTrackLabelCursor,
1195 MCFwdTrackLabelCursorType& mcFwdTrackLabelCursor,
1196 const o2::dataformats::VtxTrackRef& trackRef,
1197 const gsl::span<const GIndex>& primVerGIs,
1199 int vertexId)
1200{
1201 // labelMask (temporary) usage:
1202 // bit 13 -- ITS/TPC with ITS label (track of AB tracklet) different from TPC
1203 // bit 14 -- isNoise() == true
1204 // bit 15 -- isFake() == true (defined by the fakeness of the top level global track, i.e. if TOF is present, fake means that the track of the TPC label does not contribute to TOF cluster)
1205 // labelID = -1 -- label is not set
1206
1207 for (int src = GIndex::NSources; src--;) {
1208 int start = trackRef.getFirstEntryOfSource(src);
1209 int end = start + trackRef.getEntriesOfSource(src);
1210 mcMFTTrackLabelCursor.reserve(end - start + mcMFTTrackLabelCursor.lastIndex());
1211 mcFwdTrackLabelCursor.reserve(end - start + mcFwdTrackLabelCursor.lastIndex());
1212 mcTrackLabelCursor.reserve(end - start + mcTrackLabelCursor.lastIndex());
1213 for (int ti = start; ti < end; ti++) {
1214 const auto trackIndex = primVerGIs[ti];
1215
1216 // check if the label was already stored (or the track was rejected for some reason in the fillTrackTablesPerCollision)
1217 auto needToStore = [trackIndex](std::unordered_map<GIndex, int>& mp) {
1218 auto entry = mp.find(trackIndex);
1219 if (entry == mp.end() || entry->second == -1) {
1220 return false;
1221 }
1222 entry->second = -1;
1223 return true;
1224 };
1225
1226 if (GIndex::includesSource(src, mInputSources)) {
1227 auto mcTruth = data.getTrackMCLabel(trackIndex);
1228 MCLabels labelHolder{};
1229 if ((src == GIndex::Source::MFT) || (src == GIndex::Source::MFTMCH) || (src == GIndex::Source::MCH) || (src == GIndex::Source::MCHMID)) { // treating mft and fwd labels separately
1230 if (!needToStore(src == GIndex::Source::MFT ? mGIDToTableMFTID : mGIDToTableFwdID)) {
1231 continue;
1232 }
1233 if (mcTruth.isValid()) { // if not set, -1 will be stored
1234 labelHolder.labelID = (mToStore[mcTruth.getSourceID()][mcTruth.getEventID()])[mcTruth.getTrackID()];
1235 }
1236 if (mcTruth.isFake()) {
1237 labelHolder.fwdLabelMask |= (0x1 << 7);
1238 }
1239 if (mcTruth.isNoise()) {
1240 labelHolder.fwdLabelMask |= (0x1 << 6);
1241 }
1242 if (src == GIndex::Source::MFT) {
1243 mcMFTTrackLabelCursor(labelHolder.labelID,
1244 labelHolder.fwdLabelMask);
1245 } else {
1246 mcFwdTrackLabelCursor(labelHolder.labelID,
1247 labelHolder.fwdLabelMask);
1248 }
1249 } else {
1250 if (!needToStore(mGIDToTableID)) {
1251 continue;
1252 }
1253 if (mcTruth.isValid()) { // if not set, -1 will be stored
1254 labelHolder.labelID = (mToStore[mcTruth.getSourceID()][mcTruth.getEventID()])[mcTruth.getTrackID()]; // defined by TPC if it contributes, otherwise: by ITS
1255 if (mcTruth.isFake()) {
1256 labelHolder.labelMask |= (0x1 << 15);
1257 }
1258 if (trackIndex.includesDet(DetID::TPC) && trackIndex.getSource() != GIndex::Source::TPC) { // this is global track
1259 auto contributorsGID = data.getSingleDetectorRefs(trackIndex);
1260 if (contributorsGID[GIndex::Source::ITSTPC].isIndexSet()) { // there is a match to ITS tracks or ITSAB tracklet!
1261 if (data.getTrackMCLabel(contributorsGID[GIndex::Source::ITSTPC]).isFake()) {
1262 labelHolder.labelMask |= (0x1 << 13);
1263 }
1264 }
1265 }
1266 if (trackIndex.includesDet(DetID::ITS)) {
1267 auto itsGID = data.getITSContributorGID(trackIndex);
1268 auto itsSource = itsGID.getSource();
1269 if (itsSource == GIndex::ITS) {
1270 auto& itsTrack = data.getITSTrack(itsGID);
1271 for (unsigned int iL = 0; iL < 7; ++iL) {
1272 if (itsTrack.isFakeOnLayer(iL)) {
1273 labelHolder.labelMask |= (0x1 << iL);
1274 }
1275 }
1276 } else if (itsSource == GIndex::ITSAB) {
1277 labelHolder.labelMask |= (data.getTrackMCLabel(itsGID).isFake() << 12);
1278 }
1279 }
1280
1281 } else if (mcTruth.isNoise()) {
1282 labelHolder.labelMask |= (0x1 << 14);
1283 }
1284 mcTrackLabelCursor(labelHolder.labelID, labelHolder.labelMask);
1285 }
1286 }
1287 }
1288 }
1289
1290 // filling the tables with the strangeness tracking labels
1291 auto sTrackLabels = data.getStrangeTracksMCLabels();
1292 // check if vertexId and vertexId + 1 maps into mVertexStrLUT
1293 if (!(vertexId < 0 || vertexId >= mVertexStrLUT.size() - 1)) {
1294 mcTrackLabelCursor.reserve(mVertexStrLUT[vertexId + 1] + mcTrackLabelCursor.lastIndex());
1295 for (int iS{mVertexStrLUT[vertexId]}; iS < mVertexStrLUT[vertexId + 1]; ++iS) {
1296 auto& collStrTrk = mCollisionStrTrk[iS];
1297 auto& label = sTrackLabels[collStrTrk.second];
1298 MCLabels labelHolder;
1299 labelHolder.labelID = label.isValid() ? (mToStore[label.getSourceID()][label.getEventID()])[label.getTrackID()] : -1;
1300 labelHolder.labelMask = (label.isFake() << 15) | (label.isNoise() << 14);
1301 mcTrackLabelCursor(labelHolder.labelID, labelHolder.labelMask);
1302 }
1303 }
1304}
1305
1306template <typename V0CursorType, typename CascadeCursorType, typename Decay3BodyCursorType>
1307void AODProducerWorkflowDPL::fillSecondaryVertices(const o2::globaltracking::RecoContainer& recoData, V0CursorType& v0Cursor, CascadeCursorType& cascadeCursor, Decay3BodyCursorType& decay3BodyCursor)
1308{
1309
1310 auto v0s = recoData.getV0sIdx();
1311 auto cascades = recoData.getCascadesIdx();
1312 auto decays3Body = recoData.getDecays3BodyIdx();
1313
1314 v0Cursor.reserve(v0s.size());
1315 // filling v0s table
1316 for (size_t iv0 = 0; iv0 < v0s.size(); iv0++) {
1317 const auto& v0 = v0s[iv0];
1318 auto trPosID = v0.getProngID(0);
1319 auto trNegID = v0.getProngID(1);
1320 uint8_t v0flags = v0.getBits();
1321 int posTableIdx = -1, negTableIdx = -1, collID = -1;
1322 auto item = mGIDToTableID.find(trPosID);
1323 if (item != mGIDToTableID.end()) {
1324 posTableIdx = item->second;
1325 } else {
1326 LOG(warn) << "Could not find a positive track index for prong ID " << trPosID;
1327 }
1328 item = mGIDToTableID.find(trNegID);
1329 if (item != mGIDToTableID.end()) {
1330 negTableIdx = item->second;
1331 } else {
1332 LOG(warn) << "Could not find a negative track index for prong ID " << trNegID;
1333 }
1334 auto itemV = mVtxToTableCollID.find(v0.getVertexID());
1335 if (itemV == mVtxToTableCollID.end()) {
1336 LOG(warn) << "Could not find V0 collisionID for the vertex ID " << v0.getVertexID();
1337 } else {
1338 collID = itemV->second;
1339 }
1340 if (posTableIdx != -1 and negTableIdx != -1 and collID != -1) {
1341 v0Cursor(collID, posTableIdx, negTableIdx, v0flags);
1342 mV0ToTableID[int(iv0)] = mTableV0ID++;
1343 }
1344 }
1345
1346 // filling cascades table
1347 cascadeCursor.reserve(cascades.size());
1348 for (auto& cascade : cascades) {
1349 auto itemV0 = mV0ToTableID.find(cascade.getV0ID());
1350 if (itemV0 == mV0ToTableID.end()) {
1351 continue;
1352 }
1353 int v0tableID = itemV0->second, bachTableIdx = -1, collID = -1;
1354 auto bachelorID = cascade.getBachelorID();
1355 auto item = mGIDToTableID.find(bachelorID);
1356 if (item != mGIDToTableID.end()) {
1357 bachTableIdx = item->second;
1358 } else {
1359 LOG(warn) << "Could not find a bachelor track index";
1360 continue;
1361 }
1362 auto itemV = mVtxToTableCollID.find(cascade.getVertexID());
1363 if (itemV != mVtxToTableCollID.end()) {
1364 collID = itemV->second;
1365 } else {
1366 LOG(warn) << "Could not find cascade collisionID for the vertex ID " << cascade.getVertexID();
1367 continue;
1368 }
1369 cascadeCursor(collID, v0tableID, bachTableIdx);
1370 }
1371
1372 // filling 3 body decays table
1373 decay3BodyCursor.reserve(decays3Body.size());
1374 for (size_t i3Body = 0; i3Body < decays3Body.size(); i3Body++) {
1375 const auto& decay3Body = decays3Body[i3Body];
1376 GIndex trIDs[3]{
1377 decay3Body.getProngID(0),
1378 decay3Body.getProngID(1),
1379 decay3Body.getProngID(2)};
1380 int tableIdx[3]{-1, -1, -1}, collID = -1;
1381 bool missing{false};
1382 for (int i{0}; i < 3; ++i) {
1383 auto item = mGIDToTableID.find(trIDs[i]);
1384 if (item != mGIDToTableID.end()) {
1385 tableIdx[i] = item->second;
1386 } else {
1387 LOG(warn) << fmt::format("Could not find a track index for prong ID {}", (int)trIDs[i]);
1388 missing = true;
1389 }
1390 }
1391 auto itemV = mVtxToTableCollID.find(decay3Body.getVertexID());
1392 if (itemV == mVtxToTableCollID.end()) {
1393 LOG(warn) << "Could not find 3 body collisionID for the vertex ID " << decay3Body.getVertexID();
1394 missing = true;
1395 } else {
1396 collID = itemV->second;
1397 }
1398 if (missing) {
1399 continue;
1400 }
1401 decay3BodyCursor(collID, tableIdx[0], tableIdx[1], tableIdx[2]);
1402 }
1403}
1404
1405template <typename FwdTrkClsCursorType>
1406void AODProducerWorkflowDPL::addClustersToFwdTrkClsTable(const o2::globaltracking::RecoContainer& recoData, FwdTrkClsCursorType& fwdTrkClsCursor, GIndex trackID, int fwdTrackId)
1407{
1408 const auto& mchTracks = recoData.getMCHTracks();
1409 const auto& mchmidMatches = recoData.getMCHMIDMatches();
1410 const auto& mchClusters = recoData.getMCHTrackClusters();
1411
1412 int mchTrackID = -1;
1413 if (trackID.getSource() == GIndex::MCH) { // This is an MCH track
1414 mchTrackID = trackID.getIndex();
1415 } else if (trackID.getSource() == GIndex::MCHMID) { // This is an MCH-MID track
1416 auto mchmidMatch = mchmidMatches[trackID.getIndex()];
1417 mchTrackID = mchmidMatch.getMCHRef().getIndex();
1418 } // Others are Global Forward Tracks, their clusters will be or were added with the corresponding MCH track
1419
1420 if (mchTrackID > -1 && mchTrackID < mchTracks.size()) {
1421 const auto& mchTrack = mchTracks[mchTrackID];
1422 fwdTrkClsCursor.reserve(mchTrack.getNClusters() + fwdTrkClsCursor.lastIndex());
1423 int first = mchTrack.getFirstClusterIdx();
1424 int last = mchTrack.getLastClusterIdx();
1425 for (int i = first; i <= last; i++) {
1426 const auto& cluster = mchClusters[i];
1427 fwdTrkClsCursor(fwdTrackId,
1428 truncateFloatFraction(cluster.x, mMuonCl),
1429 truncateFloatFraction(cluster.y, mMuonCl),
1430 truncateFloatFraction(cluster.z, mMuonCl),
1431 (((cluster.ey < 5.) & 0x1) << 12) | (((cluster.ex < 5.) & 0x1) << 11) | cluster.getDEId());
1432 }
1433 }
1434}
1435
1436template <typename HMPCursorType>
1437void AODProducerWorkflowDPL::fillHMPID(const o2::globaltracking::RecoContainer& recoData, HMPCursorType& hmpCursor)
1438{
1439 auto hmpMatches = recoData.getHMPMatches();
1440
1441 hmpCursor.reserve(hmpMatches.size());
1442
1443 // filling HMPs table
1444 for (size_t iHmp = 0; iHmp < hmpMatches.size(); iHmp++) {
1445
1446 const auto& match = hmpMatches[iHmp];
1447
1448 float xTrk, yTrk, theta, phi;
1449 float xMip, yMip;
1450 int charge, nph;
1451
1452 match.getHMPIDtrk(xTrk, yTrk, theta, phi);
1453 match.getHMPIDmip(xMip, yMip, charge, nph);
1454
1455 auto photChargeVec = match.getPhotCharge();
1456
1457 float photChargeVec2[10]; // = {0.,0.,0.,0.,0.,0.,0.,0.,0.,0.};
1458
1459 for (Int_t i = 0; i < 10; i++) {
1460 photChargeVec2[i] = photChargeVec[i];
1461 }
1462 auto tref = mGIDToTableID.find(match.getTrackRef());
1463 if (tref != mGIDToTableID.end()) {
1464 hmpCursor(tref->second, match.getHMPsignal(), xTrk, yTrk, xMip, yMip, nph, charge, match.getIdxHMPClus(), match.getHmpMom(), photChargeVec2);
1465 } else {
1466 LOG(error) << "Could not find AOD track table entry for HMP-matched track " << match.getTrackRef().asString();
1467 }
1468 }
1469}
1470
1471void AODProducerWorkflowDPL::prepareStrangenessTracking(const o2::globaltracking::RecoContainer& recoData)
1472{
1473 auto v0s = recoData.getV0sIdx();
1474 auto cascades = recoData.getCascadesIdx();
1475 auto decays3Body = recoData.getDecays3BodyIdx();
1476
1477 int sTrkID = 0;
1478 mCollisionStrTrk.clear();
1479 mCollisionStrTrk.reserve(recoData.getStrangeTracks().size());
1480 mVertexStrLUT.clear();
1481 mVertexStrLUT.resize(recoData.getPrimaryVertices().size() + 1, 0);
1482 for (auto& sTrk : recoData.getStrangeTracks()) {
1483 auto ITSIndex = GIndex{sTrk.mITSRef, GIndex::ITS};
1484 int vtxId{0};
1485 if (sTrk.mPartType == dataformats::kStrkV0) {
1486 vtxId = v0s[sTrk.mDecayRef].getVertexID();
1487 } else if (sTrk.mPartType == dataformats::kStrkCascade) {
1488 vtxId = cascades[sTrk.mDecayRef].getVertexID();
1489 } else {
1490 vtxId = decays3Body[sTrk.mDecayRef].getVertexID();
1491 }
1492 mCollisionStrTrk.emplace_back(vtxId, sTrkID++);
1493 mVertexStrLUT[vtxId]++;
1494 }
1495 std::exclusive_scan(mVertexStrLUT.begin(), mVertexStrLUT.end(), mVertexStrLUT.begin(), 0);
1496
1497 // sort by collision ID
1498 std::sort(mCollisionStrTrk.begin(), mCollisionStrTrk.end(), [](const auto& a, const auto& b) { return a.first < b.first; });
1499 mStrTrkIndices.clear();
1500 mStrTrkIndices.resize(mCollisionStrTrk.size(), -1);
1501}
1502
1503template <typename V0C, typename CC, typename D3BC>
1504void AODProducerWorkflowDPL::fillStrangenessTrackingTables(const o2::globaltracking::RecoContainer& recoData, V0C& v0Curs, CC& cascCurs, D3BC& d3BodyCurs)
1505{
1506 int itsTableIdx = -1;
1507 int sTrkID = 0;
1508 int nV0 = 0;
1509 int nCasc = 0;
1510 int nD3Body = 0;
1511
1512 for (const auto& sTrk : recoData.getStrangeTracks()) {
1513 if (sTrk.mPartType == dataformats::kStrkV0) {
1514 nV0++;
1515 } else if (sTrk.mPartType == dataformats::kStrkCascade) {
1516 nCasc++;
1517 } else {
1518 nD3Body++;
1519 }
1520 }
1521
1522 v0Curs.reserve(nV0);
1523 cascCurs.reserve(nCasc);
1524 d3BodyCurs.reserve(nD3Body);
1525
1526 for (const auto& sTrk : recoData.getStrangeTracks()) {
1527 auto ITSIndex = GIndex{sTrk.mITSRef, GIndex::ITS};
1528 auto item = mGIDToTableID.find(ITSIndex);
1529 if (item != mGIDToTableID.end()) {
1530 itsTableIdx = item->second;
1531 } else {
1532 LOG(warn) << "Could not find a ITS strange track index " << ITSIndex;
1533 continue;
1534 }
1535 if (sTrk.mPartType == dataformats::kStrkV0) {
1536 v0Curs(mStrTrkIndices[sTrkID++],
1537 itsTableIdx,
1538 sTrk.mDecayRef,
1539 sTrk.mDecayVtx[0],
1540 sTrk.mDecayVtx[1],
1541 sTrk.mDecayVtx[2],
1542 sTrk.mMasses[0],
1543 sTrk.mMasses[1],
1544 sTrk.mMatchChi2,
1545 sTrk.mTopoChi2,
1546 sTrk.getAverageClusterSize());
1547 } else if (sTrk.mPartType == dataformats::kStrkCascade) {
1548 cascCurs(mStrTrkIndices[sTrkID++],
1549 itsTableIdx,
1550 sTrk.mDecayRef,
1551 sTrk.mDecayVtx[0],
1552 sTrk.mDecayVtx[1],
1553 sTrk.mDecayVtx[2],
1554 sTrk.mMasses[0],
1555 sTrk.mMasses[1],
1556 sTrk.mMatchChi2,
1557 sTrk.mTopoChi2,
1558 sTrk.getAverageClusterSize());
1559 } else {
1560 d3BodyCurs(mStrTrkIndices[sTrkID++],
1561 itsTableIdx,
1562 sTrk.mDecayRef,
1563 sTrk.mDecayVtx[0],
1564 sTrk.mDecayVtx[1],
1565 sTrk.mDecayVtx[2],
1566 sTrk.mMasses[0],
1567 sTrk.mMasses[1],
1568 sTrk.mMatchChi2,
1569 sTrk.mTopoChi2,
1570 sTrk.getAverageClusterSize());
1571 }
1572 }
1573}
1574
1575void AODProducerWorkflowDPL::countTPCClusters(const o2::globaltracking::RecoContainer& data)
1576{
1577 const auto& tpcTracks = data.getTPCTracks();
1578 const auto& tpcClusRefs = data.getTPCTracksClusterRefs();
1579 const auto& tpcClusShMap = data.clusterShMapTPC;
1580 const auto& tpcClusAcc = data.getTPCClusters();
1581 constexpr int maxRows = 152;
1582 constexpr int neighbour = 2;
1583 int ntr = tpcTracks.size();
1584 mTPCCounters.clear();
1585 mTPCCounters.resize(ntr);
1586#ifdef WITH_OPENMP
1587 int ngroup = std::min(50, std::max(1, ntr / mNThreads));
1588#pragma omp parallel for schedule(dynamic, ngroup) num_threads(mNThreads)
1589#endif
1590 for (int itr = 0; itr < ntr; itr++) {
1591 std::array<bool, maxRows> clMap{}, shMap{};
1592 uint8_t sectorIndex, rowIndex;
1593 uint32_t clusterIndex;
1594 auto& counters = mTPCCounters[itr];
1595 const auto& track = tpcTracks[itr];
1596 for (int i = 0; i < track.getNClusterReferences(); i++) {
1597 o2::tpc::TrackTPC::getClusterReference(tpcClusRefs, i, sectorIndex, rowIndex, clusterIndex, track.getClusterRef());
1598 unsigned int absoluteIndex = tpcClusAcc.clusterOffset[sectorIndex][rowIndex] + clusterIndex;
1599 clMap[rowIndex] = true;
1600 if (tpcClusShMap[absoluteIndex] & o2::gpu::GPUTPCGMMergedTrackHit::flagShared) {
1601 if (!shMap[rowIndex]) {
1602 counters.shared++;
1603 }
1604 shMap[rowIndex] = true;
1605 }
1606 }
1607 int last = -1;
1608 for (int i = 0; i < maxRows; i++) {
1609 if (clMap[i]) {
1610 counters.crossed++;
1611 counters.found++;
1612 last = i;
1613 } else if ((i - last) <= neighbour) {
1614 counters.crossed++;
1615 } else {
1616 int lim = std::min(i + 1 + neighbour, maxRows);
1617 for (int j = i + 1; j < lim; j++) {
1618 if (clMap[j]) {
1619 counters.crossed++;
1620 break;
1621 }
1622 }
1623 }
1624 }
1625 }
1626}
1627
1628uint8_t AODProducerWorkflowDPL::getTRDPattern(const o2::trd::TrackTRD& track)
1629{
1630 uint8_t pattern = 0;
1631 for (int il = o2::trd::TrackTRD::EGPUTRDTrack::kNLayers - 1; il >= 0; il--) {
1632 if (track.getTrackletIndex(il) != -1) {
1633 pattern |= 0x1 << il;
1634 }
1635 }
1636 if (track.getHasNeighbor()) {
1637 pattern |= 0x1 << 6;
1638 }
1639 if (track.getHasPadrowCrossing()) {
1640 pattern |= 0x1 << 7;
1641 }
1642 return pattern;
1643}
1644
1645template <typename TCaloHandler, typename TCaloCursor, typename TCaloTRGCursor, typename TMCCaloLabelCursor>
1646void AODProducerWorkflowDPL::addToCaloTable(TCaloHandler& caloHandler, TCaloCursor& caloCellCursor, TCaloTRGCursor& caloTRGCursor,
1647 TMCCaloLabelCursor& mcCaloCellLabelCursor, int eventID, int bcID, int8_t caloType)
1648{
1649 auto inputEvent = caloHandler.buildEvent(eventID);
1650 auto cellsInEvent = inputEvent.mCells; // get cells belonging to current event
1651 auto cellMClabels = inputEvent.mMCCellLabels; // get MC labels belonging to current event (only implemented for EMCal currently!)
1652 caloCellCursor.reserve(cellsInEvent.size() + caloCellCursor.lastIndex());
1653 caloTRGCursor.reserve(cellsInEvent.size() + caloTRGCursor.lastIndex());
1654 if (mUseMC) {
1655 mcCaloCellLabelCursor.reserve(cellsInEvent.size() + mcCaloCellLabelCursor.lastIndex());
1656 }
1657 for (auto iCell = 0U; iCell < cellsInEvent.size(); iCell++) {
1658 caloCellCursor(bcID,
1659 CellHelper::getCellNumber(cellsInEvent[iCell]),
1660 truncateFloatFraction(CellHelper::getAmplitude(cellsInEvent[iCell]), mCaloAmp),
1661 truncateFloatFraction(CellHelper::getTimeStamp(cellsInEvent[iCell]), mCaloTime),
1662 cellsInEvent[iCell].getType(),
1663 caloType); // 1 = emcal, -1 = undefined, 0 = phos
1664
1665 // todo: fix dummy values in CellHelper when it is clear what is filled for trigger information
1666 if (CellHelper::isTRU(cellsInEvent[iCell])) { // Write only trigger cells into this table
1667 caloTRGCursor(bcID,
1668 CellHelper::getFastOrAbsID(cellsInEvent[iCell]),
1669 CellHelper::getLnAmplitude(cellsInEvent[iCell]),
1670 CellHelper::getTriggerBits(cellsInEvent[iCell]),
1671 caloType);
1672 }
1673 if (mUseMC) {
1674 // Common for PHOS and EMCAL
1675 // loop over all MC Labels for the current cell
1676 std::vector<int32_t> particleIds;
1677 std::vector<float> amplitudeFraction;
1678 if (!mEMCselectLeading) {
1679 particleIds.reserve(cellMClabels.size());
1680 amplitudeFraction.reserve(cellMClabels.size());
1681 }
1682 float tmpMaxAmplitude = 0;
1683 int32_t tmpindex = 0;
1684 for (auto& mclabel : cellMClabels[iCell]) {
1685 // do not fill noise lables!
1686 if (mclabel.isValid()) {
1687 if (mEMCselectLeading) {
1688 if (mclabel.getAmplitudeFraction() > tmpMaxAmplitude) {
1689 // Check if this MCparticle added to be kept?
1690 if (mToStore.at(mclabel.getSourceID()).at(mclabel.getEventID()).find(mclabel.getTrackID()) !=
1691 mToStore.at(mclabel.getSourceID()).at(mclabel.getEventID()).end()) {
1692 tmpMaxAmplitude = mclabel.getAmplitudeFraction();
1693 tmpindex = (mToStore.at(mclabel.getSourceID()).at(mclabel.getEventID())).at(mclabel.getTrackID());
1694 }
1695 }
1696 } else {
1697 auto trackStore = mToStore.at(mclabel.getSourceID()).at(mclabel.getEventID());
1698 auto iter = trackStore.find(mclabel.getTrackID());
1699 if (iter != trackStore.end()) {
1700 amplitudeFraction.emplace_back(mclabel.getAmplitudeFraction());
1701 particleIds.emplace_back(iter->second);
1702 } else {
1703 particleIds.emplace_back(-1); // should the mc particle not be in mToStore make sure something (e.g. -1) is saved in particleIds so the length of particleIds is the same es amplitudeFraction!
1704 amplitudeFraction.emplace_back(0.f);
1705 LOG(warn) << "CaloTable: Could not find track for mclabel (" << mclabel.getSourceID() << "," << mclabel.getEventID() << "," << mclabel.getTrackID() << ") in the AOD MC store";
1706 if (mMCKineReader) {
1707 auto mctrack = mMCKineReader->getTrack(mclabel);
1708 TVector3 vec;
1709 mctrack->GetStartVertex(vec);
1710 LOG(warn) << " ... this track is of PDG " << mctrack->GetPdgCode() << " produced by " << mctrack->getProdProcessAsString() << " at (" << vec.X() << "," << vec.Y() << "," << vec.Z() << ")";
1711 }
1712 }
1713 }
1714 }
1715 } // end of loop over all MC Labels for the current cell
1716 if (mEMCselectLeading) {
1717 amplitudeFraction.emplace_back(tmpMaxAmplitude);
1718 particleIds.emplace_back(tmpindex);
1719 }
1720 if (particleIds.size() == 0) {
1721 particleIds.emplace_back(-1);
1722 amplitudeFraction.emplace_back(0.f);
1723 }
1724 mcCaloCellLabelCursor(particleIds,
1725 amplitudeFraction);
1726 }
1727 } // end of loop over cells in current event
1728}
1729
1730// fill calo related tables (cells and calotrigger table)
1731template <typename TCaloCursor, typename TCaloTRGCursor, typename TMCCaloLabelCursor>
1732void AODProducerWorkflowDPL::fillCaloTable(TCaloCursor& caloCellCursor, TCaloTRGCursor& caloTRGCursor,
1733 TMCCaloLabelCursor& mcCaloCellLabelCursor, const std::map<uint64_t, int>& bcsMap,
1735{
1736 // get calo information
1737 auto caloEMCCells = data.getEMCALCells();
1738 auto caloEMCCellsTRGR = data.getEMCALTriggers();
1739 auto mcCaloEMCCellLabels = data.getEMCALCellsMCLabels();
1740
1741 auto caloPHOSCells = data.getPHOSCells();
1742 auto caloPHOSCellsTRGR = data.getPHOSTriggers();
1743 auto mcCaloPHOSCellLabels = data.getPHOSCellsMCLabels();
1744
1745 if (!mInputSources[GIndex::PHS]) {
1746 caloPHOSCells = {};
1747 caloPHOSCellsTRGR = {};
1748 mcCaloPHOSCellLabels = {};
1749 }
1750
1751 if (!mInputSources[GIndex::EMC]) {
1752 caloEMCCells = {};
1753 caloEMCCellsTRGR = {};
1754 mcCaloEMCCellLabels = {};
1755 }
1756
1759
1760 // get cell belonging to an eveffillnt instead of timeframe
1761 emcEventHandler.reset();
1762 emcEventHandler.setCellData(caloEMCCells, caloEMCCellsTRGR);
1763 emcEventHandler.setCellMCTruthContainer(mcCaloEMCCellLabels);
1764
1765 phsEventHandler.reset();
1766 phsEventHandler.setCellData(caloPHOSCells, caloPHOSCellsTRGR);
1767 phsEventHandler.setCellMCTruthContainer(mcCaloPHOSCellLabels);
1768
1769 int emcNEvents = emcEventHandler.getNumberOfEvents();
1770 int phsNEvents = phsEventHandler.getNumberOfEvents();
1771
1772 std::vector<std::tuple<uint64_t, int8_t, int>> caloEvents; // <bc, caloType, eventID>
1773
1774 caloEvents.reserve(emcNEvents + phsNEvents);
1775
1776 for (int iev = 0; iev < emcNEvents; ++iev) {
1777 uint64_t bc = emcEventHandler.getInteractionRecordForEvent(iev).toLong();
1778 caloEvents.emplace_back(std::make_tuple(bc, 1, iev));
1779 }
1780
1781 for (int iev = 0; iev < phsNEvents; ++iev) {
1782 uint64_t bc = phsEventHandler.getInteractionRecordForEvent(iev).toLong();
1783 caloEvents.emplace_back(std::make_tuple(bc, 0, iev));
1784 }
1785
1786 std::sort(caloEvents.begin(), caloEvents.end(),
1787 [](const auto& left, const auto& right) { return std::get<0>(left) < std::get<0>(right); });
1788
1789 // loop over events
1790 for (int i = 0; i < emcNEvents + phsNEvents; ++i) {
1791 uint64_t globalBC = std::get<0>(caloEvents[i]);
1792 int8_t caloType = std::get<1>(caloEvents[i]);
1793 int eventID = std::get<2>(caloEvents[i]);
1794 auto item = bcsMap.find(globalBC);
1795 int bcID = -1;
1796 if (item != bcsMap.end()) {
1797 bcID = item->second;
1798 } else {
1799 LOG(warn) << "Error: could not find a corresponding BC ID for a calo point; globalBC = " << globalBC << ", caloType = " << (int)caloType;
1800 }
1801 if (caloType == 0) { // phos
1802 addToCaloTable(phsEventHandler, caloCellCursor, caloTRGCursor, mcCaloCellLabelCursor, eventID, bcID, caloType);
1803 }
1804 if (caloType == 1) { // emc
1805 addToCaloTable(emcEventHandler, caloCellCursor, caloTRGCursor, mcCaloCellLabelCursor, eventID, bcID, caloType);
1806 }
1807 }
1808
1809 caloEvents.clear();
1810}
1811
1813{
1814 mTimer.Stop();
1816 mLPMProdTag = ic.options().get<std::string>("lpmp-prod-tag");
1817 mAnchorPass = ic.options().get<std::string>("anchor-pass");
1818 mAnchorProd = ic.options().get<std::string>("anchor-prod");
1819 mUser = ic.options().get<std::string>("created-by");
1820 mRecoPass = ic.options().get<std::string>("reco-pass");
1821 mTFNumber = ic.options().get<int64_t>("aod-timeframe-id");
1822 mRecoOnly = ic.options().get<int>("reco-mctracks-only");
1823 mTruncate = ic.options().get<int>("enable-truncation");
1824 mRunNumber = ic.options().get<int>("run-number");
1825 mCTPReadout = ic.options().get<int>("ctpreadout-create");
1826 mNThreads = std::max(1, ic.options().get<int>("nthreads"));
1827 mEMCselectLeading = ic.options().get<bool>("emc-select-leading");
1828 mThinTracks = ic.options().get<bool>("thin-tracks");
1829 mPropTracks = ic.options().get<bool>("propagate-tracks");
1830 mMaxPropXiu = ic.options().get<float>("propagate-tracks-max-xiu");
1831 mPropMuons = ic.options().get<bool>("propagate-muons");
1832 if (auto s = ic.options().get<std::string>("with-streamers"); !s.empty()) {
1833 mStreamerFlags.set(s);
1834 if (mStreamerFlags) {
1835 LOGP(info, "Writing streamer data with mask:");
1836 LOG(info) << mStreamerFlags;
1837 } else {
1838 LOGP(warn, "Specified non-default empty streamer mask!");
1839 }
1840 }
1841 mTrackQCKeepGlobalTracks = ic.options().get<bool>("trackqc-keepglobaltracks");
1842 mTrackQCRetainOnlydEdx = ic.options().get<bool>("trackqc-retainonlydedx");
1843 mTrackQCFraction = ic.options().get<float>("trackqc-fraction");
1844 mTrackQCNTrCut = ic.options().get<int64_t>("trackqc-NTrCut");
1845 mTrackQCDCAxy = ic.options().get<float>("trackqc-tpc-dca");
1846 mTrackQCPt = ic.options().get<float>("trackqc-tpc-pt");
1847 mTrackQCNCls = ic.options().get<int>("trackqc-tpc-cls");
1848 if (auto seed = ic.options().get<int>("seed"); seed == 0) {
1849 LOGP(info, "Using random device for seeding");
1850 std::random_device rd;
1851 std::array<int, std::mt19937::state_size> seed_data{};
1852 std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd));
1853 std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
1854 mGenerator = std::mt19937(seq);
1855 } else {
1856 LOGP(info, "Using seed {} for sampling", seed);
1857 mGenerator.seed(seed);
1858 }
1859#ifdef WITH_OPENMP
1860 LOGP(info, "Multi-threaded parts will run with {} OpenMP threads", mNThreads);
1861#else
1862 mNThreads = 1;
1863 LOG(info) << "OpenMP is disabled";
1864#endif
1865 if (mTFNumber == -1L) {
1866 LOG(info) << "TFNumber will be obtained from CCDB";
1867 }
1868 if (mRunNumber == -1L) {
1869 LOG(info) << "The Run number will be obtained from DPL headers";
1870 }
1871
1872 mUseSigFiltMC = ic.options().get<bool>("mc-signal-filt");
1873
1874 // set no truncation if selected by user
1875 if (mTruncate != 1) {
1876 LOG(info) << "Truncation is not used!";
1877 mCollisionPosition = 0xFFFFFFFF;
1878 mCollisionPositionCov = 0xFFFFFFFF;
1879 mTrackX = 0xFFFFFFFF;
1880 mTrackAlpha = 0xFFFFFFFF;
1881 mTrackSnp = 0xFFFFFFFF;
1882 mTrackTgl = 0xFFFFFFFF;
1883 mTrack1Pt = 0xFFFFFFFF;
1884 mTrackChi2 = 0xFFFFFFFF;
1885 mTrackCovDiag = 0xFFFFFFFF;
1886 mTrackCovOffDiag = 0xFFFFFFFF;
1887 mTrackSignal = 0xFFFFFFFF;
1888 mTrackTime = 0xFFFFFFFF;
1889 mTPCTime0 = 0xFFFFFFFF;
1890 mTrackTimeError = 0xFFFFFFFF;
1891 mTrackPosEMCAL = 0xFFFFFFFF;
1892 mTracklets = 0xFFFFFFFF;
1893 mMcParticleW = 0xFFFFFFFF;
1894 mMcParticlePos = 0xFFFFFFFF;
1895 mMcParticleMom = 0xFFFFFFFF;
1896 mCaloAmp = 0xFFFFFFFF;
1897 mCaloTime = 0xFFFFFFFF;
1898 mCPVPos = 0xFFFFFFFF;
1899 mCPVAmpl = 0xFFFFFFFF;
1900 mMuonTr1P = 0xFFFFFFFF;
1901 mMuonTrThetaX = 0xFFFFFFFF;
1902 mMuonTrThetaY = 0xFFFFFFFF;
1903 mMuonTrZmu = 0xFFFFFFFF;
1904 mMuonTrBend = 0xFFFFFFFF;
1905 mMuonTrNonBend = 0xFFFFFFFF;
1906 mMuonTrCov = 0xFFFFFFFF;
1907 mMuonCl = 0xFFFFFFFF;
1908 mMuonClErr = 0xFFFFFFFF;
1909 mV0Time = 0xFFFFFFFF;
1910 mV0ChannelTime = 0xFFFFFFFF;
1911 mFDDTime = 0xFFFFFFFF;
1912 mFDDChannelTime = 0xFFFFFFFF;
1913 mT0Time = 0xFFFFFFFF;
1914 mT0ChannelTime = 0xFFFFFFFF;
1915 mV0Amplitude = 0xFFFFFFFF;
1916 mFDDAmplitude = 0xFFFFFFFF;
1917 mT0Amplitude = 0xFFFFFFFF;
1918 }
1919 // Initialize ZDC helper maps
1920 for (int ic = 0; ic < o2::zdc::NChannels; ic++) {
1921 mZDCEnergyMap[ic] = -std::numeric_limits<float>::infinity();
1922 }
1923 for (int ic = 0; ic < o2::zdc::NTDCChannels; ic++) {
1924 mZDCTDCMap[ic] = -std::numeric_limits<float>::infinity();
1925 }
1926
1927 std::string hepmcUpdate = ic.options().get<std::string>("hepmc-update");
1928 HepMCUpdate when = (hepmcUpdate == "never" ? HepMCUpdate::never : hepmcUpdate == "always" ? HepMCUpdate::always
1929 : hepmcUpdate == "all" ? HepMCUpdate::allKeys
1930 : HepMCUpdate::anyKey);
1931 mXSectionUpdate = when;
1932 mPdfInfoUpdate = when;
1933 mHeavyIonUpdate = when;
1934
1935 mTimer.Reset();
1936
1937 if (mStreamerFlags) {
1938 mStreamer = std::make_unique<o2::utils::TreeStreamRedirector>("AO2DStreamer.root", "RECREATE");
1939 }
1940}
1941
1942namespace
1943{
1944void add_additional_meta_info(std::vector<TString>& keys, std::vector<TString>& values)
1945{
1946 // see if we should put additional meta info (e.g. from MC)
1947 auto aod_external_meta_info_file = getenv("AOD_ADDITIONAL_METADATA_FILE");
1948 if (aod_external_meta_info_file != nullptr) {
1949 LOG(info) << "Trying to inject additional AOD meta-data from " << aod_external_meta_info_file;
1950 if (std::filesystem::exists(aod_external_meta_info_file)) {
1951 std::ifstream input_file(aod_external_meta_info_file);
1952 if (input_file) {
1953 nlohmann::json json_data;
1954 try {
1955 input_file >> json_data;
1956 } catch (nlohmann::json::parse_error& e) {
1957 std::cerr << "JSON Parse Error: " << e.what() << "\n";
1958 std::cerr << "Exception ID: " << e.id << "\n";
1959 std::cerr << "Byte position: " << e.byte << "\n";
1960 return;
1961 }
1962 // If parsing succeeds, iterate over key-value pairs
1963 for (const auto& [key, value] : json_data.items()) {
1964 LOG(info) << "Adding AOD MetaData" << key << " : " << value;
1965 keys.push_back(key.c_str());
1966 values.push_back(value.get<std::string>());
1967 }
1968 }
1969 }
1970 }
1971}
1972} // namespace
1973
1975{
1976 mTimer.Start(false);
1978 recoData.collectData(pc, *mDataRequest);
1979 updateTimeDependentParams(pc); // Make sure that this is called after the RecoContainer collect data, since some condition objects are fetched there
1980
1981 mStartIR = recoData.startIR;
1982
1983 auto primVertices = recoData.getPrimaryVertices();
1984 auto primVer2TRefs = recoData.getPrimaryVertexMatchedTrackRefs();
1985 auto primVerGIs = recoData.getPrimaryVertexMatchedTracks();
1986 auto primVerLabels = recoData.getPrimaryVertexMCLabels();
1987
1988 auto fddChData = recoData.getFDDChannelsData();
1989 auto fddRecPoints = recoData.getFDDRecPoints();
1990 auto ft0ChData = recoData.getFT0ChannelsData();
1991 auto ft0RecPoints = recoData.getFT0RecPoints();
1992 auto fv0ChData = recoData.getFV0ChannelsData();
1993 auto fv0RecPoints = recoData.getFV0RecPoints();
1994
1995 auto zdcEnergies = recoData.getZDCEnergy();
1996 auto zdcBCRecData = recoData.getZDCBCRecData();
1997 auto zdcTDCData = recoData.getZDCTDCData();
1998
1999 auto cpvClusters = recoData.getCPVClusters();
2000 auto cpvTrigRecs = recoData.getCPVTriggers();
2001
2002 auto ctpDigits = recoData.getCTPDigits();
2003 const auto& tinfo = pc.services().get<o2::framework::TimingInfo>();
2004 std::vector<o2::ctp::CTPDigit> ctpDigitsCreated;
2005 if (mCTPReadout == 1) {
2006 LOG(info) << "CTP : creating ctpreadout in AOD producer";
2007 createCTPReadout(recoData, ctpDigitsCreated, pc);
2008 LOG(info) << "CTP : ctpreadout created from AOD";
2009 ctpDigits = gsl::span<o2::ctp::CTPDigit>(ctpDigitsCreated);
2010 }
2011 LOG(debug) << "FOUND " << primVertices.size() << " primary vertices";
2012 LOG(debug) << "FOUND " << ft0RecPoints.size() << " FT0 rec. points";
2013 LOG(debug) << "FOUND " << fv0RecPoints.size() << " FV0 rec. points";
2014 LOG(debug) << "FOUND " << fddRecPoints.size() << " FDD rec. points";
2015 LOG(debug) << "FOUND " << cpvClusters.size() << " CPV clusters";
2016 LOG(debug) << "FOUND " << cpvTrigRecs.size() << " CPV trigger records";
2017
2018 LOG(info) << "FOUND " << primVertices.size() << " primary vertices";
2019
2020 using namespace o2::aodhelpers;
2021
2022 auto bcCursor = createTableCursor<o2::aod::BCs>(pc);
2023 auto bcFlagsCursor = createTableCursor<o2::aod::BCFlags>(pc);
2024 auto cascadesCursor = createTableCursor<o2::aod::Cascades>(pc);
2025 auto collisionsCursor = createTableCursor<o2::aod::Collisions>(pc);
2026 auto decay3BodyCursor = createTableCursor<o2::aod::Decay3Bodys>(pc);
2027 auto trackedCascadeCursor = createTableCursor<o2::aod::TrackedCascades>(pc);
2028 auto trackedV0Cursor = createTableCursor<o2::aod::TrackedV0s>(pc);
2029 auto tracked3BodyCurs = createTableCursor<o2::aod::Tracked3Bodys>(pc);
2030 auto fddCursor = createTableCursor<o2::aod::FDDs>(pc);
2031 auto fddExtraCursor = createTableCursor<o2::aod::FDDsExtra>(pc);
2032 auto ft0Cursor = createTableCursor<o2::aod::FT0s>(pc);
2033 auto ft0ExtraCursor = createTableCursor<o2::aod::FT0sExtra>(pc);
2034 auto fv0aCursor = createTableCursor<o2::aod::FV0As>(pc);
2035 auto fv0aExtraCursor = createTableCursor<o2::aod::FV0AsExtra>(pc);
2036 auto fwdTracksCursor = createTableCursor<o2::aod::StoredFwdTracks>(pc);
2037 auto fwdTracksCovCursor = createTableCursor<o2::aod::StoredFwdTracksCov>(pc);
2038 auto fwdTrkClsCursor = createTableCursor<o2::aod::FwdTrkCls>(pc);
2039 auto mftTracksCursor = createTableCursor<o2::aod::StoredMFTTracks>(pc);
2040 auto mftTracksCovCursor = createTableCursor<o2::aod::StoredMFTTracksCov>(pc);
2041 auto tracksCursor = createTableCursor<o2::aod::StoredTracksIU>(pc);
2042 auto tracksCovCursor = createTableCursor<o2::aod::StoredTracksCovIU>(pc);
2043 auto tracksExtraCursor = createTableCursor<o2::aod::StoredTracksExtra>(pc);
2044 auto tracksQACursor = createTableCursor<o2::aod::TracksQAVersion>(pc);
2045 auto ambigTracksCursor = createTableCursor<o2::aod::AmbiguousTracks>(pc);
2046 auto ambigMFTTracksCursor = createTableCursor<o2::aod::AmbiguousMFTTracks>(pc);
2047 auto ambigFwdTracksCursor = createTableCursor<o2::aod::AmbiguousFwdTracks>(pc);
2048 auto v0sCursor = createTableCursor<o2::aod::V0s>(pc);
2049 auto zdcCursor = createTableCursor<o2::aod::Zdcs>(pc);
2050 auto hmpCursor = createTableCursor<o2::aod::HMPIDs>(pc);
2051 auto caloCellsCursor = createTableCursor<o2::aod::Calos>(pc);
2052 auto caloCellsTRGTableCursor = createTableCursor<o2::aod::CaloTriggers>(pc);
2053 auto cpvClustersCursor = createTableCursor<o2::aod::CPVClusters>(pc);
2054 auto originCursor = createTableCursor<o2::aod::Origins>(pc);
2055
2058 if (mEnableTRDextra) {
2059 trdExtraCursor = createTableCursor<o2::aod::TRDsExtra>(pc);
2060 }
2061
2062 // Declare MC cursors type without adding the output for a table
2073 if (mUseMC) { // This creates the actual writercursor
2074 mcColLabelsCursor = createTableCursor<o2::aod::McCollisionLabels>(pc);
2075 mcCollisionsCursor = createTableCursor<o2::aod::McCollisions>(pc);
2076 hepmcXSectionsCursor = createTableCursor<o2::aod::HepMCXSections>(pc);
2077 hepmcPdfInfosCursor = createTableCursor<o2::aod::HepMCPdfInfos>(pc);
2078 hepmcHeavyIonsCursor = createTableCursor<o2::aod::HepMCHeavyIons>(pc);
2079 mcMFTTrackLabelCursor = createTableCursor<o2::aod::McMFTTrackLabels>(pc);
2080 mcFwdTrackLabelCursor = createTableCursor<o2::aod::McFwdTrackLabels>(pc);
2081 mcParticlesCursor = createTableCursor<o2::aod::StoredMcParticles_001>(pc);
2082 mcTrackLabelCursor = createTableCursor<o2::aod::McTrackLabels>(pc);
2083 mcCaloLabelsCursor = createTableCursor<o2::aod::McCaloLabels_001>(pc);
2084 }
2085
2086 std::unique_ptr<o2::steer::MCKinematicsReader> mcReader;
2087 if (mUseMC) {
2088 mcReader = std::make_unique<o2::steer::MCKinematicsReader>("collisioncontext.root");
2089 }
2090 mMCKineReader = mcReader.get(); // for use in different functions
2091 std::map<uint64_t, int> bcsMap;
2092 collectBCs(recoData, mUseMC ? mcReader->getDigitizationContext()->getEventRecords() : std::vector<o2::InteractionTimeRecord>{}, bcsMap);
2093 if (!primVer2TRefs.empty()) { // if the vertexing was done, the last slot refers to orphan tracks
2094 addRefGlobalBCsForTOF(primVer2TRefs.back(), primVerGIs, recoData, bcsMap);
2095 }
2096 // initialize the bunch crossing container for further use below
2097 mBCLookup.init(bcsMap);
2098
2099 uint64_t tfNumber;
2100 const int runNumber = (mRunNumber == -1) ? int(tinfo.runNumber) : mRunNumber;
2101 if (mTFNumber == -1L) {
2102 // TODO has to use absolute time of TF
2103 tfNumber = uint64_t(tinfo.firstTForbit) + (uint64_t(tinfo.runNumber) << 32); // getTFNumber(mStartIR, runNumber);
2104 } else {
2105 tfNumber = mTFNumber;
2106 }
2107
2108 std::vector<float> aAmplitudes, aTimes;
2109 std::vector<uint8_t> aChannels;
2110 fv0aCursor.reserve(fv0RecPoints.size());
2111 for (auto& fv0RecPoint : fv0RecPoints) {
2112 aAmplitudes.clear();
2113 aChannels.clear();
2114 aTimes.clear();
2115 const auto channelData = fv0RecPoint.getBunchChannelData(fv0ChData);
2116 for (auto& channel : channelData) {
2117 if (channel.charge > 0) {
2118 aAmplitudes.push_back(truncateFloatFraction(channel.charge, mV0Amplitude));
2119 aTimes.push_back(truncateFloatFraction(channel.time * 1.E-3, mV0ChannelTime));
2120 aChannels.push_back(channel.channel);
2121 }
2122 }
2123 uint64_t bc = fv0RecPoint.getInteractionRecord().toLong();
2124 auto item = bcsMap.find(bc);
2125 int bcID = -1;
2126 if (item != bcsMap.end()) {
2127 bcID = item->second;
2128 } else {
2129 LOG(fatal) << "Error: could not find a corresponding BC ID for a FV0 rec. point; BC = " << bc;
2130 }
2131 fv0aCursor(bcID,
2132 aAmplitudes,
2133 aChannels,
2134 truncateFloatFraction(fv0RecPoint.getCollisionGlobalMeanTime() * 1E-3, mV0Time), // ps to ns
2135 fv0RecPoint.getTrigger().getTriggersignals());
2136
2137 if (mEnableFITextra) {
2138 fv0aExtraCursor(bcID,
2139 aTimes);
2140 }
2141 }
2142
2143 std::vector<float> zdcEnergy, zdcAmplitudes, zdcTime;
2144 std::vector<uint8_t> zdcChannelsE, zdcChannelsT;
2145 zdcCursor.reserve(zdcBCRecData.size());
2146 for (auto zdcRecData : zdcBCRecData) {
2147 uint64_t bc = zdcRecData.ir.toLong();
2148 auto item = bcsMap.find(bc);
2149 int bcID = -1;
2150 if (item != bcsMap.end()) {
2151 bcID = item->second;
2152 } else {
2153 LOG(fatal) << "Error: could not find a corresponding BC ID for a ZDC rec. point; BC = " << bc;
2154 }
2155 int fe, ne, ft, nt, fi, ni;
2156 zdcRecData.getRef(fe, ne, ft, nt, fi, ni);
2157 zdcEnergy.clear();
2158 zdcChannelsE.clear();
2159 zdcAmplitudes.clear();
2160 zdcTime.clear();
2161 zdcChannelsT.clear();
2162 for (int ie = 0; ie < ne; ie++) {
2163 auto& zdcEnergyData = zdcEnergies[fe + ie];
2164 zdcEnergy.emplace_back(zdcEnergyData.energy());
2165 zdcChannelsE.emplace_back(zdcEnergyData.ch());
2166 }
2167 for (int it = 0; it < nt; it++) {
2168 auto& tdc = zdcTDCData[ft + it];
2169 zdcAmplitudes.emplace_back(tdc.amplitude());
2170 zdcTime.emplace_back(tdc.value());
2171 zdcChannelsT.emplace_back(o2::zdc::TDCSignal[tdc.ch()]);
2172 }
2173 zdcCursor(bcID,
2174 zdcEnergy,
2175 zdcChannelsE,
2176 zdcAmplitudes,
2177 zdcTime,
2178 zdcChannelsT);
2179 }
2180
2181 // keep track event/source id for each mc-collision
2182 // using map and not unordered_map to ensure
2183 // correct ordering when iterating over container elements
2184 std::vector<std::vector<int>> mcColToEvSrc;
2185
2186 if (mUseMC) {
2187 using namespace o2::aodmchelpers;
2188
2189 // filling mcCollision table
2190 int nMCCollisions = mcReader->getDigitizationContext()->getNCollisions();
2191 const auto& mcRecords = mcReader->getDigitizationContext()->getEventRecords();
2192 const auto& mcParts = mcReader->getDigitizationContext()->getEventParts();
2193
2194 // if signal filtering enabled, let's check if there are more than one source; otherwise fatalise
2195 if (mUseSigFiltMC) {
2196 std::vector<int> sourceIDs{};
2197 for (int iCol = 0; iCol < nMCCollisions; iCol++) {
2198 for (auto const& colPart : mcParts[iCol]) {
2199 int sourceID = colPart.sourceID;
2200 if (std::find(sourceIDs.begin(), sourceIDs.end(), sourceID) == sourceIDs.end()) {
2201 sourceIDs.push_back(sourceID);
2202 }
2203 if (sourceIDs.size() > 1) { // we found more than one, exit
2204 break;
2205 }
2206 }
2207 if (sourceIDs.size() > 1) { // we found more than one, exit
2208 break;
2209 }
2210 }
2211 if (sourceIDs.size() <= 1) {
2212 LOGP(fatal, "Signal filtering cannot be enabled without embedding. Please fix the configuration either enabling the embedding, or turning off the signal filtering.");
2213 }
2214 }
2215
2216 // count all parts
2217 int totalNParts = 0;
2218 for (int iCol = 0; iCol < nMCCollisions; iCol++) {
2219 totalNParts += mcParts[iCol].size();
2220 }
2221 mcCollisionsCursor.reserve(totalNParts);
2222
2223 for (int iCol = 0; iCol < nMCCollisions; iCol++) {
2224 const auto time = mcRecords[iCol].getTimeOffsetWrtBC();
2225 auto globalBC = mcRecords[iCol].toLong();
2226 auto item = bcsMap.find(globalBC);
2227 int bcID = -1;
2228 if (item != bcsMap.end()) {
2229 bcID = item->second;
2230 } else {
2231 LOG(fatal) << "Error: could not find a corresponding BC ID "
2232 << "for MC collision; BC = " << globalBC
2233 << ", mc collision = " << iCol;
2234 }
2235 auto& colParts = mcParts[iCol];
2236 auto nParts = colParts.size();
2237 for (auto colPart : colParts) {
2238 auto eventID = colPart.entryID;
2239 auto sourceID = colPart.sourceID;
2240 // enable embedding: if several colParts exist, then they are
2241 // saved as one collision
2242 if (nParts == 1 || sourceID == 0) {
2243 // FIXME:
2244 // use generators' names for generatorIDs (?)
2245 auto& header = mcReader->getMCEventHeader(sourceID, eventID);
2246 updateMCHeader(mcCollisionsCursor.cursor,
2247 hepmcXSectionsCursor.cursor,
2248 hepmcPdfInfosCursor.cursor,
2249 hepmcHeavyIonsCursor.cursor,
2250 header,
2251 iCol,
2252 bcID,
2253 time,
2254 0,
2255 sourceID);
2256 }
2257 mcColToEvSrc.emplace_back(std::vector<int>{iCol, sourceID, eventID}); // point background and injected signal events to one collision
2258 }
2259 }
2260 }
2261
2262 std::sort(mcColToEvSrc.begin(), mcColToEvSrc.end(),
2263 [](const std::vector<int>& left, const std::vector<int>& right) { return (left[0] < right[0]); });
2264
2265 // vector of FDD amplitudes
2266 int16_t aFDDAmplitudesA[8] = {0u}, aFDDAmplitudesC[8] = {0u};
2267 float aFDDTimesA[8] = {0.f}, aFDDTimesC[8] = {0.f};
2268 // filling FDD table
2269 fddCursor.reserve(fddRecPoints.size());
2270 for (const auto& fddRecPoint : fddRecPoints) {
2271 for (int i = 0; i < 8; i++) {
2272 aFDDAmplitudesA[i] = 0;
2273 aFDDAmplitudesC[i] = 0;
2274 aFDDTimesA[i] = 0.f;
2275 aFDDTimesC[i] = 0.f;
2276 }
2277 uint64_t globalBC = fddRecPoint.getInteractionRecord().toLong();
2278 uint64_t bc = globalBC;
2279 auto item = bcsMap.find(bc);
2280 int bcID = -1;
2281 if (item != bcsMap.end()) {
2282 bcID = item->second;
2283 } else {
2284 LOG(fatal) << "Error: could not find a corresponding BC ID for a FDD rec. point; BC = " << bc;
2285 }
2286 const auto channelData = fddRecPoint.getBunchChannelData(fddChData);
2287 for (const auto& channel : channelData) {
2288 if (channel.mPMNumber < 8) {
2289 aFDDAmplitudesC[channel.mPMNumber] = channel.mChargeADC; // amplitude
2290 aFDDTimesC[channel.mPMNumber] = truncateFloatFraction(channel.mTime * 1E-3, mFDDChannelTime); // time
2291 } else {
2292 aFDDAmplitudesA[channel.mPMNumber - 8] = channel.mChargeADC; // amplitude
2293 aFDDTimesA[channel.mPMNumber - 8] = truncateFloatFraction(channel.mTime * 1E-3, mFDDChannelTime); // time
2294 }
2295 }
2296
2297 fddCursor(bcID,
2298 aFDDAmplitudesA,
2299 aFDDAmplitudesC,
2300 truncateFloatFraction(fddRecPoint.getCollisionTimeA() * 1E-3, mFDDTime), // ps to ns
2301 truncateFloatFraction(fddRecPoint.getCollisionTimeC() * 1E-3, mFDDTime), // ps to ns
2302 fddRecPoint.getTrigger().getTriggersignals());
2303 if (mEnableFITextra) {
2304 fddExtraCursor(bcID,
2305 aFDDTimesA,
2306 aFDDTimesC);
2307 }
2308 }
2309
2310 // filling FT0 table
2311 std::vector<float> aAmplitudesA, aAmplitudesC, aTimesA, aTimesC;
2312 std::vector<uint8_t> aChannelsA, aChannelsC;
2313 ft0Cursor.reserve(ft0RecPoints.size());
2314 for (auto& ft0RecPoint : ft0RecPoints) {
2315 aAmplitudesA.clear();
2316 aAmplitudesC.clear();
2317 aTimesA.clear();
2318 aTimesC.clear();
2319 aChannelsA.clear();
2320 aChannelsC.clear();
2321 const auto channelData = ft0RecPoint.getBunchChannelData(ft0ChData);
2322 for (auto& channel : channelData) {
2323 // TODO: switch to calibrated amplitude
2324 if (channel.QTCAmpl > 0) {
2325 constexpr int nFT0ChannelsAside = o2::ft0::Geometry::NCellsA * 4;
2326 if (channel.ChId < nFT0ChannelsAside) {
2327 aChannelsA.push_back(channel.ChId);
2328 aAmplitudesA.push_back(truncateFloatFraction(channel.QTCAmpl, mT0Amplitude));
2329 aTimesA.push_back(truncateFloatFraction(channel.CFDTime * 1E-3, mT0ChannelTime));
2330 } else {
2331 aChannelsC.push_back(channel.ChId - nFT0ChannelsAside);
2332 aAmplitudesC.push_back(truncateFloatFraction(channel.QTCAmpl, mT0Amplitude));
2333 aTimesC.push_back(truncateFloatFraction(channel.CFDTime * 1E-3, mT0ChannelTime));
2334 }
2335 }
2336 }
2337 uint64_t globalBC = ft0RecPoint.getInteractionRecord().toLong();
2338 uint64_t bc = globalBC;
2339 auto item = bcsMap.find(bc);
2340 int bcID = -1;
2341 if (item != bcsMap.end()) {
2342 bcID = item->second;
2343 } else {
2344 LOG(fatal) << "Error: could not find a corresponding BC ID for a FT0 rec. point; BC = " << bc;
2345 }
2346 ft0Cursor(bcID,
2347 aAmplitudesA,
2348 aChannelsA,
2349 aAmplitudesC,
2350 aChannelsC,
2351 truncateFloatFraction(ft0RecPoint.getCollisionTimeA() * 1E-3, mT0Time), // ps to ns
2352 truncateFloatFraction(ft0RecPoint.getCollisionTimeC() * 1E-3, mT0Time), // ps to ns
2353 ft0RecPoint.getTrigger().getTriggersignals());
2354 if (mEnableFITextra) {
2355 ft0ExtraCursor(bcID,
2356 aTimesA,
2357 aTimesC);
2358 }
2359 }
2360
2361 if (mUseMC) {
2362 // filling MC collision labels
2363 mcColLabelsCursor.reserve(primVerLabels.size());
2364 for (auto& label : primVerLabels) {
2365 auto it = std::find_if(mcColToEvSrc.begin(), mcColToEvSrc.end(),
2366 [&label](const auto& mcColInfo) { return mcColInfo[1] == label.getSourceID() && mcColInfo[2] == label.getEventID(); });
2367 int32_t mcCollisionID = -1;
2368 if (it != mcColToEvSrc.end()) {
2369 mcCollisionID = it->at(0);
2370 }
2371 uint16_t mcMask = 0; // todo: set mask using normalized weights?
2372 mcColLabelsCursor(mcCollisionID, mcMask);
2373 }
2374 }
2375
2376 cacheTriggers(recoData);
2377 countTPCClusters(recoData);
2378
2379 int collisionID = 0;
2380 mIndexTableMFT.resize(recoData.getMFTTracks().size());
2381 mIndexTableFwd.resize(recoData.getMCHTracks().size());
2382
2383 auto& trackReffwd = primVer2TRefs.back();
2384 fillIndexTablesPerCollision(trackReffwd, primVerGIs, recoData);
2385 collisionID = 0;
2386 for (auto& vertex : primVertices) {
2387 auto& trackReffwd = primVer2TRefs[collisionID];
2388 fillIndexTablesPerCollision(trackReffwd, primVerGIs, recoData); // this function must follow the same track order as 'fillTrackTablesPerCollision' to fill the map of track indices
2389 collisionID++;
2390 }
2391
2393 prepareStrangenessTracking(recoData);
2394
2395 mGIDToTableFwdID.clear(); // reset the tables to be used by 'fillTrackTablesPerCollision'
2396 mGIDToTableMFTID.clear();
2397
2398 if (mPropTracks || mThinTracks) {
2399 auto v0s = recoData.getV0sIdx();
2400 auto cascades = recoData.getCascadesIdx();
2401 auto decays3Body = recoData.getDecays3BodyIdx();
2402 mGIDUsedBySVtx.reserve(v0s.size() * 2 + cascades.size() + decays3Body.size() * 3);
2403 for (const auto& v0 : v0s) {
2404 mGIDUsedBySVtx.insert(v0.getProngID(0));
2405 mGIDUsedBySVtx.insert(v0.getProngID(1));
2406 }
2407 for (const auto& cascade : cascades) {
2408 mGIDUsedBySVtx.insert(cascade.getBachelorID());
2409 }
2410 for (const auto& id3Body : decays3Body) {
2411 mGIDUsedBySVtx.insert(id3Body.getProngID(0));
2412 mGIDUsedBySVtx.insert(id3Body.getProngID(1));
2413 mGIDUsedBySVtx.insert(id3Body.getProngID(2));
2414 }
2415
2416 mGIDUsedByStr.reserve(recoData.getStrangeTracks().size());
2417 for (const auto& sTrk : recoData.getStrangeTracks()) {
2418 mGIDUsedByStr.emplace(sTrk.mITSRef, GIndex::ITS);
2419 }
2420 }
2421
2422 mCurrentTRDTrigID = 0; // reinitialize index for TRD trigger record search
2423 // filling unassigned tracks first
2424 // so that all unassigned tracks are stored in the beginning of the table together
2425 auto& trackRef = primVer2TRefs.back(); // references to unassigned tracks are at the end
2426 // fixme: interaction time is undefined for unassigned tracks (?)
2427 fillTrackTablesPerCollision(-1, std::uint64_t(-1), trackRef, primVerGIs, recoData, tracksCursor, tracksCovCursor, tracksExtraCursor, tracksQACursor, trdExtraCursor,
2428 ambigTracksCursor, mftTracksCursor, mftTracksCovCursor, ambigMFTTracksCursor,
2429 fwdTracksCursor, fwdTracksCovCursor, ambigFwdTracksCursor, fwdTrkClsCursor, bcsMap);
2430
2431 mCurrentTRDTrigID = 0; // reinitialize index for TRD trigger record search
2432 // filling collisions and tracks into tables
2433 collisionID = 0;
2434 collisionsCursor.reserve(primVertices.size());
2435 for (auto& vertex : primVertices) {
2436 auto& cov = vertex.getCov();
2437 auto& timeStamp = vertex.getTimeStamp(); // this is a relative time
2438 const double interactionTime = timeStamp.getTimeStamp() * 1E3; // mus to ns
2439 uint64_t globalBC = relativeTime_to_GlobalBC(interactionTime);
2440 uint64_t localBC = relativeTime_to_LocalBC(interactionTime);
2441 LOG(debug) << "global BC " << globalBC << " local BC " << localBC << " relative interaction time " << interactionTime;
2442 // collision timestamp in ns wrt the beginning of collision BC
2443 const float relInteractionTime = static_cast<float>(localBC * o2::constants::lhc::LHCBunchSpacingNS - interactionTime);
2444 auto item = bcsMap.find(globalBC);
2445 int bcID = -1;
2446 if (item != bcsMap.end()) {
2447 bcID = item->second;
2448 } else {
2449 LOG(fatal) << "Error: could not find a corresponding BC ID for a collision; BC = " << globalBC << ", collisionID = " << collisionID;
2450 }
2451 collisionsCursor(bcID,
2452 truncateFloatFraction(vertex.getX(), mCollisionPosition),
2453 truncateFloatFraction(vertex.getY(), mCollisionPosition),
2454 truncateFloatFraction(vertex.getZ(), mCollisionPosition),
2455 truncateFloatFraction(cov[0], mCollisionPositionCov),
2456 truncateFloatFraction(cov[1], mCollisionPositionCov),
2457 truncateFloatFraction(cov[2], mCollisionPositionCov),
2458 truncateFloatFraction(cov[3], mCollisionPositionCov),
2459 truncateFloatFraction(cov[4], mCollisionPositionCov),
2460 truncateFloatFraction(cov[5], mCollisionPositionCov),
2461 vertex.getFlags(),
2462 truncateFloatFraction(vertex.getChi2(), mCollisionPositionCov),
2463 vertex.getNContributors(),
2464 truncateFloatFraction(relInteractionTime, mCollisionPosition),
2465 truncateFloatFraction(timeStamp.getTimeStampError() * 1E3, mCollisionPositionCov));
2466 mVtxToTableCollID[collisionID] = mTableCollID++;
2467
2468 auto& trackRef = primVer2TRefs[collisionID];
2469 // passing interaction time in [ps]
2470 fillTrackTablesPerCollision(collisionID, globalBC, trackRef, primVerGIs, recoData, tracksCursor, tracksCovCursor, tracksExtraCursor, tracksQACursor, trdExtraCursor, ambigTracksCursor,
2471 mftTracksCursor, mftTracksCovCursor, ambigMFTTracksCursor,
2472 fwdTracksCursor, fwdTracksCovCursor, ambigFwdTracksCursor, fwdTrkClsCursor, bcsMap);
2473 collisionID++;
2474 }
2475
2476 fillSecondaryVertices(recoData, v0sCursor, cascadesCursor, decay3BodyCursor);
2477 fillHMPID(recoData, hmpCursor);
2478 fillStrangenessTrackingTables(recoData, trackedV0Cursor, trackedCascadeCursor, tracked3BodyCurs);
2479
2480 // helper map for fast search of a corresponding class mask for a bc
2481 auto emcalIncomplete = filterEMCALIncomplete(recoData.getEMCALTriggers());
2482 std::unordered_map<uint64_t, std::pair<uint64_t, uint64_t>> bcToClassMask;
2483 if (mInputSources[GID::CTP]) {
2484 LOG(debug) << "CTP input available";
2485 for (auto& ctpDigit : ctpDigits) {
2486 uint64_t bc = ctpDigit.intRecord.toLong();
2487 uint64_t classMask = ctpDigit.CTPClassMask.to_ulong();
2488 uint64_t inputMask = ctpDigit.CTPInputMask.to_ulong();
2489 if (emcalIncomplete.find(bc) != emcalIncomplete.end()) {
2490 // reject EMCAL triggers as BC was rejected as incomplete at readout level
2491 auto classMaskOrig = classMask;
2492 classMask = classMask & ~mEMCALTrgClassMask;
2493 LOG(debug) << "Found EMCAL incomplete event, mask before " << std::bitset<64>(classMaskOrig) << ", after " << std::bitset<64>(classMask);
2494 }
2495 bcToClassMask[bc] = {classMask, inputMask};
2496 // LOG(debug) << Form("classmask:0x%llx", classMask);
2497 }
2498 }
2499
2500 // filling BC table
2501 bcCursor.reserve(bcsMap.size());
2502 for (auto& item : bcsMap) {
2503 uint64_t bc = item.first;
2504 std::pair<uint64_t, uint64_t> masks{0, 0};
2505 if (mInputSources[GID::CTP]) {
2506 auto bcClassPair = bcToClassMask.find(bc);
2507 if (bcClassPair != bcToClassMask.end()) {
2508 masks = bcClassPair->second;
2509 }
2510 }
2511 bcCursor(runNumber,
2512 bc,
2513 masks.first,
2514 masks.second);
2515 }
2516
2517 bcToClassMask.clear();
2518
2519 // filling BC flags table:
2520 auto bcFlags = fillBCFlags(recoData, bcsMap);
2521 bcFlagsCursor.reserve(bcFlags.size());
2522 for (auto f : bcFlags) {
2523 bcFlagsCursor(f);
2524 }
2525
2526 // fill cpvcluster table
2527 if (mInputSources[GIndex::CPV]) {
2528 float posX, posZ;
2529 cpvClustersCursor.reserve(cpvTrigRecs.size());
2530 for (auto& cpvEvent : cpvTrigRecs) {
2531 uint64_t bc = cpvEvent.getBCData().toLong();
2532 auto item = bcsMap.find(bc);
2533 int bcID = -1;
2534 if (item != bcsMap.end()) {
2535 bcID = item->second;
2536 } else {
2537 LOG(fatal) << "Error: could not find a corresponding BC ID for a CPV Trigger Record; BC = " << bc;
2538 }
2539 for (int iClu = cpvEvent.getFirstEntry(); iClu < cpvEvent.getFirstEntry() + cpvEvent.getNumberOfObjects(); iClu++) {
2540 auto& clu = cpvClusters[iClu];
2541 clu.getLocalPosition(posX, posZ);
2542 cpvClustersCursor(bcID,
2543 truncateFloatFraction(posX, mCPVPos),
2544 truncateFloatFraction(posZ, mCPVPos),
2545 truncateFloatFraction(clu.getEnergy(), mCPVAmpl),
2546 clu.getPackedClusterStatus());
2547 }
2548 }
2549 }
2550
2551 if (mUseMC) {
2552 TStopwatch timer;
2553 timer.Start();
2554 // filling mc particles table
2555 fillMCParticlesTable(*mcReader,
2556 mcParticlesCursor.cursor,
2557 primVer2TRefs,
2558 primVerGIs,
2559 recoData,
2560 mcColToEvSrc);
2561 timer.Stop();
2562 LOG(info) << "FILL MC took " << timer.RealTime() << " s";
2563 mcColToEvSrc.clear();
2564
2565 // ------------------------------------------------------
2566 // filling track labels
2567
2568 // need to go through labels in the same order as for tracks
2569 fillMCTrackLabelsTable(mcTrackLabelCursor, mcMFTTrackLabelCursor, mcFwdTrackLabelCursor, primVer2TRefs.back(), primVerGIs, recoData);
2570 for (auto iref = 0U; iref < primVer2TRefs.size() - 1; iref++) {
2571 auto& trackRef = primVer2TRefs[iref];
2572 fillMCTrackLabelsTable(mcTrackLabelCursor, mcMFTTrackLabelCursor, mcFwdTrackLabelCursor, trackRef, primVerGIs, recoData, iref);
2573 }
2574 }
2575
2576 // Fill calo tables and if MC also the MCCaloTable, therefore, has to be after fillMCParticlesTable call!
2577 if (mInputSources[GIndex::PHS] || mInputSources[GIndex::EMC]) {
2578 fillCaloTable(caloCellsCursor, caloCellsTRGTableCursor, mcCaloLabelsCursor, bcsMap, recoData);
2579 }
2580
2581 bcsMap.clear();
2582 clearMCKeepStore(mToStore);
2583 mGIDToTableID.clear();
2584 mTableTrID = 0;
2585 mGIDToTableFwdID.clear();
2586 mTableTrFwdID = 0;
2587 mGIDToTableMFTID.clear();
2588 mTableTrMFTID = 0;
2589 mVtxToTableCollID.clear();
2590 mTableCollID = 0;
2591 mV0ToTableID.clear();
2592 mTableV0ID = 0;
2593
2594 mIndexTableFwd.clear();
2595 mIndexFwdID = 0;
2596 mIndexTableMFT.clear();
2597 mIndexMFTID = 0;
2598
2599 mBCLookup.clear();
2600
2601 mGIDUsedBySVtx.clear();
2602 mGIDUsedByStr.clear();
2603
2604 originCursor(tfNumber);
2605
2606 // sending metadata to writer
2607 TString dataType = mUseMC ? "MC" : "RAW";
2608 TString O2Version = o2::fullVersion();
2609 TString ROOTVersion = ROOT_RELEASE;
2610 mMetaDataKeys = {"DataType", "Run", "O2Version", "ROOTVersion", "RecoPassName", "AnchorProduction", "AnchorPassName", "LPMProductionTag", "CreatedBy"};
2611 mMetaDataVals = {dataType, "3", O2Version, ROOTVersion, mRecoPass, mAnchorProd, mAnchorPass, mLPMProdTag, mUser};
2612 add_additional_meta_info(mMetaDataKeys, mMetaDataVals);
2613
2614 pc.outputs().snapshot(Output{"AMD", "AODMetadataKeys", 0}, mMetaDataKeys);
2615 pc.outputs().snapshot(Output{"AMD", "AODMetadataVals", 0}, mMetaDataVals);
2616
2617 pc.outputs().snapshot(Output{"TFN", "TFNumber", 0}, tfNumber);
2618 pc.outputs().snapshot(Output{"TFF", "TFFilename", 0}, "");
2619
2620 mTimer.Stop();
2621}
2622
2623void AODProducerWorkflowDPL::cacheTriggers(const o2::globaltracking::RecoContainer& recoData)
2624{
2625 // ITS tracks->ROF
2626 {
2627 mITSROFs.clear();
2628 const auto& rofs = recoData.getITSTracksROFRecords();
2629 uint16_t count = 0;
2630 for (const auto& rof : rofs) {
2631 int first = rof.getFirstEntry(), last = first + rof.getNEntries();
2632 for (int i = first; i < last; i++) {
2633 mITSROFs.push_back(count);
2634 }
2635 count++;
2636 }
2637 }
2638 // MFT tracks->ROF
2639 {
2640 mMFTROFs.clear();
2641 const auto& rofs = recoData.getMFTTracksROFRecords();
2642 uint16_t count = 0;
2643 for (const auto& rof : rofs) {
2644 int first = rof.getFirstEntry(), last = first + rof.getNEntries();
2645 for (int i = first; i < last; i++) {
2646 mMFTROFs.push_back(count);
2647 }
2648 count++;
2649 }
2650 }
2651 // ITSTPCTRD tracks -> TRD trigger
2652 {
2653 mITSTPCTRDTriggers.clear();
2654 const auto& itstpctrigs = recoData.getITSTPCTRDTriggers();
2655 int count = 0;
2656 for (const auto& trig : itstpctrigs) {
2657 int first = trig.getFirstTrack(), last = first + trig.getNumberOfTracks();
2658 for (int i = first; i < last; i++) {
2659 mITSTPCTRDTriggers.push_back(count);
2660 }
2661 count++;
2662 }
2663 }
2664 // TPCTRD tracks -> TRD trigger
2665 {
2666 mTPCTRDTriggers.clear();
2667 const auto& tpctrigs = recoData.getTPCTRDTriggers();
2668 int count = 0;
2669 for (const auto& trig : tpctrigs) {
2670 int first = trig.getFirstTrack(), last = first + trig.getNumberOfTracks();
2671 for (int i = first; i < last; i++) {
2672 mTPCTRDTriggers.push_back(count);
2673 }
2674 count++;
2675 }
2676 }
2677 // MCH tracks->ROF
2678 {
2679 mMCHROFs.clear();
2680 const auto& rofs = recoData.getMCHTracksROFRecords();
2681 uint16_t count = 0;
2682 for (const auto& rof : rofs) {
2683 int first = rof.getFirstIdx(), last = first + rof.getNEntries();
2684 for (int i = first; i < last; i++) {
2685 mMCHROFs.push_back(count);
2686 }
2687 count++;
2688 }
2689 }
2690}
2691
2692AODProducerWorkflowDPL::TrackExtraInfo AODProducerWorkflowDPL::processBarrelTrack(int collisionID, std::uint64_t collisionBC, GIndex trackIndex,
2693 const o2::globaltracking::RecoContainer& data, const std::map<uint64_t, int>& bcsMap)
2694{
2695 TrackExtraInfo extraInfoHolder;
2696 if (collisionID < 0) {
2697 extraInfoHolder.flags |= o2::aod::track::OrphanTrack;
2698 }
2699 bool needBCSlice = collisionID < 0; // track is associated to multiple vertices
2700 uint64_t bcOfTimeRef = collisionBC - mStartIR.toLong(); // by default track time is wrt collision BC (unless no collision assigned)
2701
2702 auto setTrackTime = [&](double t, double terr, bool gaussian) {
2703 // set track time and error, for ambiguous tracks define the bcSlice as it was used in vertex-track association
2704 // provided track time (wrt TF start) and its error should be in ns, gaussian flag tells if the error is assumed to be gaussin or half-interval
2705 if (!gaussian) {
2706 extraInfoHolder.flags |= o2::aod::track::TrackTimeResIsRange;
2707 }
2708 extraInfoHolder.trackTimeRes = terr;
2709 if (needBCSlice) { // need to define BC slice
2710 double error = this->mTimeMarginTrackTime + (gaussian ? extraInfoHolder.trackTimeRes * this->mNSigmaTimeTrack : extraInfoHolder.trackTimeRes);
2711 bcOfTimeRef = fillBCSlice(extraInfoHolder.bcSlice, t - error, t + error, bcsMap);
2712 }
2713 extraInfoHolder.trackTime = float(t - bcOfTimeRef * o2::constants::lhc::LHCBunchSpacingNS);
2714 extraInfoHolder.diffBCRef = int(bcOfTimeRef);
2715 LOGP(debug, "time : {}/{} -> {}/{} -> trunc: {}/{} CollID: {} Amb: {}", t, terr, t - bcOfTimeRef * o2::constants::lhc::LHCBunchSpacingNS, terr,
2716 truncateFloatFraction(extraInfoHolder.trackTime, mTrackTime), truncateFloatFraction(extraInfoHolder.trackTimeRes, mTrackTimeError),
2717 collisionID, trackIndex.isAmbiguous());
2718 };
2719 auto contributorsGID = data.getSingleDetectorRefs(trackIndex);
2720 const auto& trackPar = data.getTrackParam(trackIndex);
2721 extraInfoHolder.flags |= trackPar.getPID() << 28;
2722 auto src = trackIndex.getSource();
2723 if (contributorsGID[GIndex::Source::TOF].isIndexSet()) { // ITS-TPC-TRD-TOF, ITS-TPC-TOF, TPC-TRD-TOF, TPC-TOF
2724 const auto& tofMatch = data.getTOFMatch(trackIndex);
2725 extraInfoHolder.tofChi2 = tofMatch.getChi2();
2726 const auto& tofInt = tofMatch.getLTIntegralOut();
2727 float intLen = tofInt.getL();
2728 extraInfoHolder.length = intLen;
2729 const float mass = o2::constants::physics::MassPionCharged; // default pid = pion
2730 if (tofInt.getTOF(o2::track::PID::Pion) > 0.f) {
2731 float expBeta = (intLen / (tofInt.getTOF(o2::track::PID::Pion) * cSpeed));
2732 if (expBeta > o2::constants::math::Almost1) {
2734 }
2735 extraInfoHolder.tofExpMom = mass * expBeta / std::sqrt(1.f - expBeta * expBeta);
2736 }
2737 // correct the time of the track
2738 const double massZ = o2::track::PID::getMass2Z(trackPar.getPID());
2739 const double energy = sqrt((massZ * massZ) + (extraInfoHolder.tofExpMom * extraInfoHolder.tofExpMom));
2740 const double exp = extraInfoHolder.length * energy / (cSpeed * extraInfoHolder.tofExpMom);
2741 auto tofSignal = (tofMatch.getSignal() - exp) * 1e-3; // time in ns wrt TF start
2742 setTrackTime(tofSignal, 0.2, true); // FIXME: calculate actual resolution (if possible?)
2743 }
2744 if (contributorsGID[GIndex::Source::TRD].isIndexSet()) { // ITS-TPC-TRD-TOF, TPC-TRD-TOF, TPC-TRD, ITS-TPC-TRD
2745 const auto& trdOrig = data.getTrack<o2::trd::TrackTRD>(contributorsGID[GIndex::Source::TRD]); // refitted TRD trac
2746 extraInfoHolder.trdChi2 = trdOrig.getChi2();
2747 extraInfoHolder.trdSignal = trdOrig.getSignal();
2748 extraInfoHolder.trdPattern = getTRDPattern(trdOrig);
2749 if (extraInfoHolder.trackTimeRes < 0.) { // time is not set yet, this is possible only for TPC-TRD and ITS-TPC-TRD tracks, since those with TOF are set upstream
2750 // TRD is triggered: time uncertainty is within a BC
2751 const auto& trdTrig = (src == GIndex::Source::TPCTRD) ? data.getTPCTRDTriggers()[mTPCTRDTriggers[trackIndex.getIndex()]] : data.getITSTPCTRDTriggers()[mITSTPCTRDTriggers[trackIndex.getIndex()]];
2752 double ttrig = trdTrig.getBCData().differenceInBC(mStartIR) * o2::constants::lhc::LHCBunchSpacingNS; // 1st get time wrt TF start
2753 setTrackTime(ttrig, 1., true); // FIXME: calculate actual resolution (if possible?)
2754 }
2755 }
2756 if (contributorsGID[GIndex::Source::ITS].isIndexSet()) {
2757 const auto& itsTrack = data.getITSTrack(contributorsGID[GIndex::ITS]);
2758 int nClusters = itsTrack.getNClusters();
2759 float chi2 = itsTrack.getChi2();
2760 extraInfoHolder.itsChi2NCl = nClusters != 0 ? chi2 / (float)nClusters : 0;
2761 extraInfoHolder.itsClusterSizes = itsTrack.getClusterSizes();
2762 if (src == GIndex::ITS) { // standalone ITS track should set its time from the ROF
2763 const auto& rof = data.getITSTracksROFRecords()[mITSROFs[trackIndex.getIndex()]];
2764 double t = rof.getBCData().differenceInBC(mStartIR) * o2::constants::lhc::LHCBunchSpacingNS + mITSROFrameHalfLengthNS + mITSROFBiasNS;
2765 setTrackTime(t, mITSROFrameHalfLengthNS, false);
2766 }
2767 } else if (contributorsGID[GIndex::Source::ITSAB].isIndexSet()) { // this is an ITS-TPC afterburner contributor
2768 extraInfoHolder.itsClusterSizes = data.getITSABRefs()[contributorsGID[GIndex::Source::ITSAB].getIndex()].getClusterSizes();
2769 }
2770 if (contributorsGID[GIndex::Source::TPC].isIndexSet()) {
2771 const auto& tpcOrig = data.getTPCTrack(contributorsGID[GIndex::TPC]);
2772 const auto& tpcClData = mTPCCounters[contributorsGID[GIndex::TPC]];
2773 const auto& dEdx = tpcOrig.getdEdx().dEdxTotTPC > 0 ? tpcOrig.getdEdx() : tpcOrig.getdEdxAlt();
2774 if (tpcOrig.getdEdx().dEdxTotTPC == 0) {
2775 extraInfoHolder.flags |= o2::aod::track::TPCdEdxAlt;
2776 }
2777 if (tpcOrig.hasASideClusters()) {
2778 extraInfoHolder.flags |= o2::aod::track::TPCSideA;
2779 }
2780 if (tpcOrig.hasCSideClusters()) {
2781 extraInfoHolder.flags |= o2::aod::track::TPCSideC;
2782 }
2783 extraInfoHolder.tpcInnerParam = tpcOrig.getP() / tpcOrig.getAbsCharge();
2784 extraInfoHolder.tpcChi2NCl = tpcOrig.getNClusters() ? tpcOrig.getChi2() / tpcOrig.getNClusters() : 0;
2785 extraInfoHolder.tpcSignal = dEdx.dEdxTotTPC;
2786 extraInfoHolder.tpcNClsFindable = tpcOrig.getNClusters();
2787 extraInfoHolder.tpcNClsFindableMinusFound = tpcOrig.getNClusters() - tpcClData.found;
2788 extraInfoHolder.tpcNClsFindableMinusCrossedRows = tpcOrig.getNClusters() - tpcClData.crossed;
2789 extraInfoHolder.tpcNClsShared = tpcClData.shared;
2790 uint32_t clsUsedForPID = dEdx.NHitsIROC + dEdx.NHitsOROC1 + dEdx.NHitsOROC2 + dEdx.NHitsOROC3;
2791 extraInfoHolder.tpcNClsFindableMinusPID = tpcOrig.getNClusters() - clsUsedForPID;
2792 if (src == GIndex::TPC) { // standalone TPC track should set its time from their timebins range
2793 if (needBCSlice) {
2794 double t = (tpcOrig.getTime0() + 0.5 * (tpcOrig.getDeltaTFwd() - tpcOrig.getDeltaTBwd())) * mTPCBinNS; // central value
2795 double terr = 0.5 * (tpcOrig.getDeltaTFwd() + tpcOrig.getDeltaTBwd()) * mTPCBinNS;
2796 double err = mTimeMarginTrackTime + terr;
2797 bcOfTimeRef = fillBCSlice(extraInfoHolder.bcSlice, t - err, t + err, bcsMap);
2798 }
2800 p.setDeltaTFwd(tpcOrig.getDeltaTFwd());
2801 p.setDeltaTBwd(tpcOrig.getDeltaTBwd());
2802 extraInfoHolder.trackTimeRes = p.getTimeErr();
2803 extraInfoHolder.trackTime = float(tpcOrig.getTime0() * mTPCBinNS - bcOfTimeRef * o2::constants::lhc::LHCBunchSpacingNS);
2804 extraInfoHolder.diffBCRef = int(bcOfTimeRef);
2805 extraInfoHolder.isTPConly = true; // no truncation
2806 extraInfoHolder.flags |= o2::aod::track::TrackTimeAsym;
2807 } else if (src == GIndex::ITSTPC) { // its-tpc matched tracks have gaussian time error and the time was not set above
2808 const auto& trITSTPC = data.getTPCITSTrack(trackIndex);
2809 auto ts = trITSTPC.getTimeMUS();
2810 setTrackTime(ts.getTimeStamp() * 1.e3, ts.getTimeStampError() * 1.e3, true);
2811 }
2812 }
2813
2814 extrapolateToCalorimeters(extraInfoHolder, data.getTrackParamOut(trackIndex));
2815 // set bit encoding for PVContributor property as part of the flag field
2816 if (trackIndex.isPVContributor()) {
2817 extraInfoHolder.flags |= o2::aod::track::PVContributor;
2818 }
2819 return extraInfoHolder;
2820}
2821
2822AODProducerWorkflowDPL::TrackQA AODProducerWorkflowDPL::processBarrelTrackQA(int collisionID, std::uint64_t collisionBC, GIndex trackIndex,
2823 const o2::globaltracking::RecoContainer& data, const std::map<uint64_t, int>& bcsMap)
2824{
2825 TrackQA trackQAHolder;
2826 auto contributorsGID = data.getTPCContributorGID(trackIndex);
2827 const auto& trackPar = data.getTrackParam(trackIndex);
2828 if (contributorsGID.isIndexSet()) {
2829 auto prop = o2::base::Propagator::Instance();
2830 const auto& tpcOrig = data.getTPCTrack(contributorsGID);
2833 const o2::base::Propagator::MatCorrType mMatType = o2::base::Propagator::MatCorrType::USEMatCorrLUT;
2834 const o2::dataformats::VertexBase v = mVtx.getMeanVertex(collisionID < 0 ? 0.f : data.getPrimaryVertex(collisionID).getZ());
2835 std::array<float, 2> dcaInfo{-999., -999.};
2836 if (prop->propagateToDCABxByBz({v.getX(), v.getY(), v.getZ()}, tpcTMP, 2.f, mMatType, &dcaInfo)) {
2837 trackQAHolder.tpcdcaR = 100. * dcaInfo[0] / sqrt(1. + trackPar.getQ2Pt() * trackPar.getQ2Pt());
2838 trackQAHolder.tpcdcaZ = 100. * dcaInfo[1] / sqrt(1. + trackPar.getQ2Pt() * trackPar.getQ2Pt());
2839 }
2840 // This allows to safely clamp any float to one byte, using the
2841 // minmal/maximum values as under-/overflow borders and rounding to the nearest integer
2842 auto safeInt8Clamp = [](auto value) -> int8_t {
2843 using ValType = decltype(value);
2844 return static_cast<int8_t>(TMath::Nint(std::clamp(value, static_cast<ValType>(std::numeric_limits<int8_t>::min()), static_cast<ValType>(std::numeric_limits<int8_t>::max()))));
2845 };
2846 auto safeUInt8Clamp = [](auto value) -> uint8_t {
2847 using ValType = decltype(value);
2848 return static_cast<uint8_t>(TMath::Nint(std::clamp(value, static_cast<ValType>(std::numeric_limits<uint8_t>::min()), static_cast<ValType>(std::numeric_limits<uint8_t>::max()))));
2849 };
2850
2852 uint8_t clusterCounters[8] = {0};
2853 {
2854 uint8_t sectorIndex, rowIndex;
2855 uint32_t clusterIndex;
2856 const auto& tpcClusRefs = data.getTPCTracksClusterRefs();
2857 for (int i = 0; i < tpcOrig.getNClusterReferences(); i++) {
2858 o2::tpc::TrackTPC::getClusterReference(tpcClusRefs, i, sectorIndex, rowIndex, clusterIndex, tpcOrig.getClusterRef());
2859 char indexTracklet = (rowIndex % 152) / 19;
2860 clusterCounters[indexTracklet]++;
2861 }
2862 }
2863 uint8_t byteMask = 0;
2864 for (int i = 0; i < 8; i++) {
2865 if (clusterCounters[i] > 5) {
2866 byteMask |= (1 << i);
2867 }
2868 }
2869 trackQAHolder.tpcTime0 = tpcOrig.getTime0();
2870 trackQAHolder.tpcClusterByteMask = byteMask;
2871 const auto& dEdxInfoAlt = tpcOrig.getdEdxAlt(); // tpcOrig.getdEdx()
2872 const float dEdxNorm = (dEdxInfoAlt.dEdxTotTPC > 0) ? 100. / dEdxInfoAlt.dEdxTotTPC : 0;
2873 trackQAHolder.tpcdEdxNorm = dEdxInfoAlt.dEdxTotTPC;
2874 trackQAHolder.tpcdEdxMax0R = safeUInt8Clamp(dEdxInfoAlt.dEdxMaxIROC * dEdxNorm);
2875 trackQAHolder.tpcdEdxMax1R = safeUInt8Clamp(dEdxInfoAlt.dEdxMaxOROC1 * dEdxNorm);
2876 trackQAHolder.tpcdEdxMax2R = safeUInt8Clamp(dEdxInfoAlt.dEdxMaxOROC2 * dEdxNorm);
2877 trackQAHolder.tpcdEdxMax3R = safeUInt8Clamp(dEdxInfoAlt.dEdxMaxOROC3 * dEdxNorm);
2878 //
2879 trackQAHolder.tpcdEdxTot0R = safeUInt8Clamp(dEdxInfoAlt.dEdxTotIROC * dEdxNorm);
2880 trackQAHolder.tpcdEdxTot1R = safeUInt8Clamp(dEdxInfoAlt.dEdxTotOROC1 * dEdxNorm);
2881 trackQAHolder.tpcdEdxTot2R = safeUInt8Clamp(dEdxInfoAlt.dEdxTotOROC2 * dEdxNorm);
2882 trackQAHolder.tpcdEdxTot3R = safeUInt8Clamp(dEdxInfoAlt.dEdxTotOROC3 * dEdxNorm);
2884 float scaleTOF{0};
2885 auto contributorsGIDA = data.getSingleDetectorRefs(trackIndex);
2886 if (contributorsGIDA[GIndex::Source::TOF].isIndexSet()) { // ITS-TPC-TRD-TOF, ITS-TPC-TOF, TPC-TRD-TOF, TPC-TOF
2887 const auto& tofMatch = data.getTOFMatch(trackIndex);
2888 const float qpt = trackPar.getQ2Pt();
2890 trackQAHolder.dTofdX = safeInt8Clamp(tofMatch.getDXatTOF() / scaleTOF);
2891 trackQAHolder.dTofdZ = safeInt8Clamp(tofMatch.getDZatTOF() / scaleTOF);
2892 }
2893
2894 // Add matching information at a reference point (defined by
2895 // o2::aod::track::trackQARefRadius) in the same frame as the global track
2896 // without material corrections and error propagation
2897 if (auto itsContGID = data.getITSContributorGID(trackIndex); itsContGID.isIndexSet() && itsContGID.getSource() != GIndex::ITSAB) {
2898 const auto& itsOrig = data.getITSTrack(itsContGID);
2899 o2::track::TrackPar gloCopy = trackPar;
2900 o2::track::TrackPar itsCopy = itsOrig.getParamOut();
2901 o2::track::TrackPar tpcCopy = tpcOrig;
2902 if (prop->propagateToX(gloCopy, o2::aod::track::trackQARefRadius, prop->getNominalBz(), o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, mMatCorr) &&
2903 prop->propagateToAlphaX(tpcCopy, gloCopy.getAlpha(), o2::aod::track::trackQARefRadius, false, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, 1, mMatCorr) &&
2904 prop->propagateToAlphaX(itsCopy, gloCopy.getAlpha(), o2::aod::track::trackQARefRadius, false, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, 1, mMatCorr)) {
2905 // All tracks are now at the same radius and in the same frame and we can calculate the deltas wrt. to the global track
2906 // The scale is defined by the global track scaling depending on beta0
2907 const float beta0 = std::sqrt(std::min(50.f / tpcOrig.getdEdx().dEdxMaxTPC, 1.f));
2908 const float qpt = gloCopy.getQ2Pt();
2909 const float x = qpt / beta0;
2910 // scaling is defined as sigmaBins/sqrt(p0^2 + (p1 * q/pt / beta)^2)
2911 auto scaleCont = [&x](int i) -> float {
2913 };
2914 auto scaleGlo = [&x](int i) -> float {
2916 };
2917
2918 // Calculate deltas for contributors
2919 trackQAHolder.dRefContY = safeInt8Clamp((itsCopy.getY() - tpcCopy.getY()) * scaleCont(0));
2920 trackQAHolder.dRefContZ = safeInt8Clamp((itsCopy.getZ() - tpcCopy.getZ()) * scaleCont(1));
2921 trackQAHolder.dRefContSnp = safeInt8Clamp((itsCopy.getSnp() - tpcCopy.getSnp()) * scaleCont(2));
2922 trackQAHolder.dRefContTgl = safeInt8Clamp((itsCopy.getTgl() - tpcCopy.getTgl()) * scaleCont(3));
2923 trackQAHolder.dRefContQ2Pt = safeInt8Clamp((itsCopy.getQ2Pt() - tpcCopy.getQ2Pt()) * scaleCont(4));
2924 // Calculate deltas for global track against averaged contributors
2925 trackQAHolder.dRefGloY = safeInt8Clamp(((itsCopy.getY() + tpcCopy.getY()) * 0.5f - gloCopy.getY()) * scaleGlo(0));
2926 trackQAHolder.dRefGloZ = safeInt8Clamp(((itsCopy.getZ() + tpcCopy.getZ()) * 0.5f - gloCopy.getZ()) * scaleGlo(1));
2927 trackQAHolder.dRefGloSnp = safeInt8Clamp(((itsCopy.getSnp() + tpcCopy.getSnp()) * 0.5f - gloCopy.getSnp()) * scaleGlo(2));
2928 trackQAHolder.dRefGloTgl = safeInt8Clamp(((itsCopy.getTgl() + tpcCopy.getTgl()) * 0.5f - gloCopy.getTgl()) * scaleGlo(3));
2929 trackQAHolder.dRefGloQ2Pt = safeInt8Clamp(((itsCopy.getQ2Pt() + tpcCopy.getQ2Pt()) * 0.5f - gloCopy.getQ2Pt()) * scaleGlo(4));
2930 //
2931
2932 if (mStreamerFlags[AODProducerStreamerFlags::TrackQA]) {
2933 (*mStreamer) << "trackQA"
2934 << "trackITSOrig=" << itsOrig
2935 << "trackTPCOrig=" << tpcOrig
2936 << "trackITSTPCOrig=" << trackPar
2937 << "trackITSProp=" << itsCopy
2938 << "trackTPCProp=" << tpcCopy
2939 << "trackITSTPCProp=" << gloCopy
2940 << "refRadius=" << o2::aod::track::trackQARefRadius
2941 << "scaleBins=" << o2::aod::track::trackQAScaleBins
2942 << "scaleCont0=" << scaleCont(0)
2943 << "scaleCont1=" << scaleCont(1)
2944 << "scaleCont2=" << scaleCont(2)
2945 << "scaleCont3=" << scaleCont(3)
2946 << "scaleCont4=" << scaleCont(4)
2947 << "scaleGlo0=" << scaleGlo(0)
2948 << "scaleGlo1=" << scaleGlo(1)
2949 << "scaleGlo2=" << scaleGlo(2)
2950 << "scaleGlo3=" << scaleGlo(3)
2951 << "scaleGlo4=" << scaleGlo(4)
2952 << "trackQAHolder.tpcTime0=" << trackQAHolder.tpcTime0
2953 << "trackQAHolder.tpcdEdxNorm=" << trackQAHolder.tpcdEdxNorm
2954 << "trackQAHolder.tpcdcaR=" << trackQAHolder.tpcdcaR
2955 << "trackQAHolder.tpcdcaZ=" << trackQAHolder.tpcdcaZ
2956 << "trackQAHolder.tpcdcaClusterByteMask=" << trackQAHolder.tpcClusterByteMask
2957 << "trackQAHolder.tpcdEdxMax0R=" << trackQAHolder.tpcdEdxMax0R
2958 << "trackQAHolder.tpcdEdxMax1R=" << trackQAHolder.tpcdEdxMax1R
2959 << "trackQAHolder.tpcdEdxMax2R=" << trackQAHolder.tpcdEdxMax2R
2960 << "trackQAHolder.tpcdEdxMax3R=" << trackQAHolder.tpcdEdxMax3R
2961 << "trackQAHolder.tpcdEdxTot0R=" << trackQAHolder.tpcdEdxTot0R
2962 << "trackQAHolder.tpcdEdxTot1R=" << trackQAHolder.tpcdEdxTot1R
2963 << "trackQAHolder.tpcdEdxTot2R=" << trackQAHolder.tpcdEdxTot2R
2964 << "trackQAHolder.tpcdEdxTot3R=" << trackQAHolder.tpcdEdxTot3R
2965 << "trackQAHolder.dRefContY=" << trackQAHolder.dRefContY
2966 << "trackQAHolder.dRefContZ=" << trackQAHolder.dRefContZ
2967 << "trackQAHolder.dRefContSnp=" << trackQAHolder.dRefContSnp
2968 << "trackQAHolder.dRefContTgl=" << trackQAHolder.dRefContTgl
2969 << "trackQAHolder.dRefContQ2Pt=" << trackQAHolder.dRefContQ2Pt
2970 << "trackQAHolder.dRefGloY=" << trackQAHolder.dRefGloY
2971 << "trackQAHolder.dRefGloZ=" << trackQAHolder.dRefGloZ
2972 << "trackQAHolder.dRefGloSnp=" << trackQAHolder.dRefGloSnp
2973 << "trackQAHolder.dRefGloTgl=" << trackQAHolder.dRefGloTgl
2974 << "trackQAHolder.dRefGloQ2Pt=" << trackQAHolder.dRefGloQ2Pt
2975 << "trackQAHolder.dTofdX=" << trackQAHolder.dTofdX
2976 << "trackQAHolder.dTofdZ=" << trackQAHolder.dTofdZ
2977 << "scaleTOF=" << scaleTOF
2978 << "\n";
2979 }
2980 }
2981 }
2982 }
2983
2984 return trackQAHolder;
2985}
2986
2987bool AODProducerWorkflowDPL::propagateTrackToPV(o2::track::TrackParametrizationWithError<float>& trackPar,
2989 int colID)
2990{
2991 o2::dataformats::DCA dcaInfo;
2992 dcaInfo.set(999.f, 999.f, 999.f, 999.f, 999.f);
2993 o2::dataformats::VertexBase v = mVtx.getMeanVertex(colID < 0 ? 0.f : data.getPrimaryVertex(colID).getZ());
2994 return o2::base::Propagator::Instance()->propagateToDCABxByBz(v, trackPar, 2.f, mMatCorr, &dcaInfo);
2995}
2996
2997void AODProducerWorkflowDPL::extrapolateToCalorimeters(TrackExtraInfo& extraInfoHolder, const o2::track::TrackPar& track)
2998{
2999 constexpr float XEMCAL = 440.f, XPHOS = 460.f, XEMCAL2 = XEMCAL * XEMCAL;
3000 constexpr float ETAEMCAL = 0.75; // eta of EMCAL/DCAL with margin
3001 constexpr float ZEMCALFastCheck = 460.; // Max Z (with margin to check with straightline extrapolarion)
3002 constexpr float ETADCALINNER = 0.22; // eta of the DCAL PHOS Hole (at XEMCAL)
3003 constexpr float ETAPHOS = 0.13653194; // nominal eta of the PHOS acceptance (at XPHOS): -log(tan((TMath::Pi()/2 - atan2(63, 460))/2))
3004 constexpr float ETAPHOSMARGIN = 0.17946979; // etat of the PHOS acceptance with 20 cm margin (at XPHOS): -log(tan((TMath::Pi()/2 + atan2(63+20., 460))/2)), not used, for the ref only
3005 constexpr float ETADCALPHOSSWITCH = (ETADCALINNER + ETAPHOS) / 2; // switch to DCAL to PHOS check if eta < this value
3006 constexpr short SNONE = 0, SEMCAL = 0x1, SPHOS = 0x2;
3007 constexpr short SECTORTYPE[18] = {
3008 SNONE, SNONE, SNONE, SNONE, // 0:3
3009 SEMCAL, SEMCAL, SEMCAL, SEMCAL, SEMCAL, SEMCAL, // 3:9 EMCAL only
3010 SNONE, SNONE, // 10:11
3011 SPHOS, // 12 PHOS only
3012 SPHOS | SEMCAL, SPHOS | SEMCAL, SPHOS | SEMCAL, // 13:15 PHOS & DCAL
3013 SEMCAL, // 16 DCAL only
3014 SNONE // 17
3015 };
3016
3017 o2::track::TrackPar outTr{track};
3018 auto prop = o2::base::Propagator::Instance();
3019 // 1st propagate to EMCAL nominal radius
3020 float xtrg = 0;
3021 // quick check with straight line propagtion
3022 if (!outTr.getXatLabR(XEMCAL, xtrg, prop->getNominalBz(), o2::track::DirType::DirOutward) ||
3023 (std::abs(outTr.getZAt(xtrg, 0)) > ZEMCALFastCheck) ||
3024 !prop->PropagateToXBxByBz(outTr, xtrg, 0.95, 10, o2::base::Propagator::MatCorrType::USEMatCorrLUT)) {
3025 LOGP(debug, "preliminary step: does not reach R={} {}", XEMCAL, outTr.asString());
3026 return;
3027 }
3028 // we do not necessarilly reach wanted radius in a single propagation
3029 if ((outTr.getX() * outTr.getX() + outTr.getY() * outTr.getY() < XEMCAL2) &&
3030 (!outTr.rotateParam(outTr.getPhi()) ||
3031 !outTr.getXatLabR(XEMCAL, xtrg, prop->getNominalBz(), o2::track::DirType::DirOutward) ||
3032 !prop->PropagateToXBxByBz(outTr, xtrg, 0.95, 10, o2::base::Propagator::MatCorrType::USEMatCorrLUT))) {
3033 LOGP(debug, "does not reach R={} {}", XEMCAL, outTr.asString());
3034 return;
3035 }
3036 // rotate to proper sector
3037 int sector = o2::math_utils::angle2Sector(outTr.getPhiPos());
3038
3039 auto propExactSector = [&outTr, &sector, prop](float xprop) -> bool { // propagate exactly to xprop in the proper sector frame
3040 int ntri = 0;
3041 while (ntri < 2) {
3042 auto outTrTmp = outTr;
3043 float alpha = o2::math_utils::sector2Angle(sector);
3044 if ((std::abs(outTr.getZ()) > ZEMCALFastCheck) || !outTrTmp.rotateParam(alpha) ||
3045 !prop->PropagateToXBxByBz(outTrTmp, xprop, 0.95, 10, o2::base::Propagator::MatCorrType::USEMatCorrLUT)) {
3046 LOGP(debug, "failed on rotation to {} (sector {}) or propagation to X={} {}", alpha, sector, xprop, outTrTmp.asString());
3047 return false;
3048 }
3049 // make sure we are still in the target sector
3050 int sectorTmp = o2::math_utils::angle2Sector(outTrTmp.getPhiPos());
3051 if (sectorTmp == sector) {
3052 outTr = outTrTmp;
3053 break;
3054 }
3055 sector = sectorTmp;
3056 ntri++;
3057 }
3058 if (ntri == 2) {
3059 LOGP(debug, "failed to rotate to sector, {}", outTr.asString());
3060 return false;
3061 }
3062 return true;
3063 };
3064
3065 // we are at the EMCAL X, check if we are in the good sector
3066 if (!propExactSector(XEMCAL) || SECTORTYPE[sector] == SNONE) { // propagation failed or neither EMCAL not DCAL/PHOS
3067 return;
3068 }
3069
3070 // check if we are in a good eta range
3071 float r = std::sqrt(outTr.getX() * outTr.getX() + outTr.getY() * outTr.getY()), tg = std::atan2(r, outTr.getZ());
3072 float eta = -std::log(std::tan(0.5f * tg)), etaAbs = std::abs(eta);
3073 if (etaAbs > ETAEMCAL) {
3074 LOGP(debug, "eta = {} is off at EMCAL radius", eta, outTr.asString());
3075 return;
3076 }
3077 // are we in the PHOS hole (with margin)?
3078 if ((SECTORTYPE[sector] & SPHOS) && etaAbs < ETADCALPHOSSWITCH) { // propagate to PHOS radius
3079 if (!propExactSector(XPHOS)) {
3080 return;
3081 }
3082 r = std::sqrt(outTr.getX() * outTr.getX() + outTr.getY() * outTr.getY());
3083 tg = std::atan2(r, outTr.getZ());
3084 eta = -std::log(std::tan(0.5f * tg));
3085 } else if (!(SECTORTYPE[sector] & SEMCAL)) { // are in the sector with PHOS only
3086 return;
3087 }
3088 extraInfoHolder.trackPhiEMCAL = outTr.getPhiPos();
3089 extraInfoHolder.trackEtaEMCAL = eta;
3090 LOGP(debug, "eta = {} phi = {} sector {} for {}", extraInfoHolder.trackEtaEMCAL, extraInfoHolder.trackPhiEMCAL, sector, outTr.asString());
3091 //
3092}
3093
3094std::set<uint64_t> AODProducerWorkflowDPL::filterEMCALIncomplete(const gsl::span<const o2::emcal::TriggerRecord> triggers)
3095{
3096 std::set<uint64_t> emcalIncompletes;
3097 for (const auto& trg : triggers) {
3098 if (trg.getTriggerBits() & o2::emcal::triggerbits::Inc) {
3099 // trigger record masked at incomplete at readout level
3100 emcalIncompletes.insert(trg.getBCData().toLong());
3101 }
3102 }
3103 return emcalIncompletes;
3104}
3105
3106void AODProducerWorkflowDPL::updateTimeDependentParams(ProcessingContext& pc)
3107{
3109 static bool initOnceDone = false;
3110 if (!initOnceDone) { // this params need to be queried only once
3111 initOnceDone = true;
3112 // Note: DPLAlpideParam for ITS and MFT will be loaded by the RecoContainer
3113 mSqrtS = o2::base::GRPGeomHelper::instance().getGRPLHCIF()->getSqrtS();
3114 // apply settings
3117 std::bitset<3564> bs = bcf.getBCPattern();
3118 for (auto i = 0U; i < bs.size(); i++) {
3119 if (bs.test(i)) {
3121 }
3122 }
3123
3125 mITSROFrameHalfLengthNS = 0.5 * (grpECS->isDetContinuousReadOut(o2::detectors::DetID::ITS) ? alpParamsITS.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS : alpParamsITS.roFrameLengthTrig);
3128 mMFTROFrameHalfLengthNS = 0.5 * (grpECS->isDetContinuousReadOut(o2::detectors::DetID::MFT) ? alpParamsMFT.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS : alpParamsMFT.roFrameLengthTrig);
3130
3131 // RS FIXME: this is not yet fetched from the CCDB
3133 mTPCBinNS = elParam.ZbinWidth * 1.e3;
3134
3135 const auto& pvParams = o2::vertexing::PVertexerParams::Instance();
3136 mNSigmaTimeTrack = pvParams.nSigmaTimeTrack;
3137 mTimeMarginTrackTime = pvParams.timeMarginTrackTime * 1.e3;
3138 mFieldON = std::abs(o2::base::Propagator::Instance()->getNominalBz()) > 0.01;
3139
3140 pc.inputs().get<o2::ctp::CTPConfiguration*>("ctpconfig");
3141 if (mEnableTRDextra) {
3142 mTRDLocalGain = pc.inputs().get<o2::trd::LocalGainFactor*>("trdlocalgainfactors").get();
3143 mTRDNoiseMap = pc.inputs().get<o2::trd::NoiseStatusMCM*>("trdnoisemap").get();
3144 mTRDGainCalib = pc.inputs().get<o2::trd::CalGain*>("trdgaincalib").get(); // time dependent gain
3145 }
3146 }
3147 if (mPropTracks) {
3149 }
3150}
3151
3152//_______________________________________
3154{
3155 // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level
3156 if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) {
3157 if (matcher == ConcreteDataMatcher("GLO", "GRPMAGFIELD", 0)) {
3159 }
3160 return;
3161 }
3162 if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) {
3163 LOG(info) << "ITS Alpide param updated";
3165 par.printKeyValues();
3166 return;
3167 }
3168 if (matcher == ConcreteDataMatcher("MFT", "ALPIDEPARAM", 0)) {
3169 LOG(info) << "MFT Alpide param updated";
3171 par.printKeyValues();
3172 return;
3173 }
3174 if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) {
3175 LOG(info) << "Imposing new MeanVertex: " << ((const o2::dataformats::MeanVertexObject*)obj)->asString();
3176 mVtx = *(const o2::dataformats::MeanVertexObject*)obj;
3177 return;
3178 }
3179 if (matcher == ConcreteDataMatcher("CTP", "CTPCONFIG", 0)) {
3180 // construct mask with EMCAL trigger classes for rejection of incomplete triggers
3181 auto ctpconfig = *(const o2::ctp::CTPConfiguration*)obj;
3182 mEMCALTrgClassMask = 0;
3183 for (const auto& trgclass : ctpconfig.getCTPClasses()) {
3184 if (trgclass.cluster->maskCluster[o2::detectors::DetID::EMC]) {
3185 mEMCALTrgClassMask |= trgclass.classMask;
3186 }
3187 }
3188 LOG(info) << "Loaded EMCAL trigger class mask: " << std::bitset<64>(mEMCALTrgClassMask);
3189 }
3190}
3191
3192void AODProducerWorkflowDPL::addRefGlobalBCsForTOF(const o2::dataformats::VtxTrackRef& trackRef, const gsl::span<const GIndex>& GIndices,
3193 const o2::globaltracking::RecoContainer& data, std::map<uint64_t, int>& bcsMap)
3194{
3195 // Orphan tracks need to refer to some globalBC and for tracks with TOF this BC should be whithin an orbit
3196 // from the track abs time (to guarantee time precision). Therefore, we may need to insert some dummy globalBCs
3197 // to guarantee proper reference.
3198 // complete globalBCs by dummy entries necessary to provide BC references for TOF tracks with requested precision
3199 // to provide a reference for the time of the orphan tracks we should make sure that there are no gaps longer
3200 // than needed to store the time with sufficient precision
3201
3202 // estimate max distance in BCs between TOF time and eventual reference BC
3203 int nbitsFrac = 24 - (32 - o2::math_utils::popcount(mTrackTime)); // number of bits used to encode the fractional part of float truncated by the mask
3204 int nbitsLoss = std::max(0, int(std::log2(TOFTimePrecPS))); // allowed bit loss guaranteeing needed precision in PS
3205 assert(nbitsFrac > 1);
3206 std::uint64_t maxRangePS = std::uint64_t(0x1) << (nbitsFrac + nbitsLoss);
3207 int maxGapBC = maxRangePS / (o2::constants::lhc::LHCBunchSpacingNS * 1e3); // max gap in BCs allowing to store time with required precision
3208 LOG(info) << "Max gap of " << maxGapBC << " BCs to closest globalBC reference is needed for TOF tracks to provide precision of "
3209 << TOFTimePrecPS << " ps";
3210
3211 // check if there are tracks orphan tracks at all
3212 if (!trackRef.getEntries()) {
3213 return;
3214 }
3215 // the bscMap has at least TF start BC
3216 std::uint64_t maxBC = mStartIR.toLong();
3217 const auto& tofClus = data.getTOFClusters();
3218 for (int src = GIndex::NSources; src--;) {
3219 if (!GIndex::getSourceDetectorsMask(src)[o2::detectors::DetID::TOF]) { // check only tracks with TOF contribution
3220 continue;
3221 }
3222 int start = trackRef.getFirstEntryOfSource(src);
3223 int end = start + trackRef.getEntriesOfSource(src);
3224 for (int ti = start; ti < end; ti++) {
3225 auto& trackIndex = GIndices[ti];
3226 const auto& tofMatch = data.getTOFMatch(trackIndex);
3227 const auto& tofInt = tofMatch.getLTIntegralOut();
3228 float intLen = tofInt.getL();
3229 float tofExpMom = 0.;
3230 if (tofInt.getTOF(o2::track::PID::Pion) > 0.f) {
3231 float expBeta = (intLen / (tofInt.getTOF(o2::track::PID::Pion) * cSpeed));
3232 if (expBeta > o2::constants::math::Almost1) {
3234 }
3235 tofExpMom = o2::constants::physics::MassPionCharged * expBeta / std::sqrt(1.f - expBeta * expBeta);
3236 } else {
3237 continue;
3238 }
3239 double massZ = o2::track::PID::getMass2Z(data.getTrackParam(trackIndex).getPID());
3240 double energy = sqrt((massZ * massZ) + (tofExpMom * tofExpMom));
3241 double exp = intLen * energy / (cSpeed * tofExpMom);
3242 auto tofSignal = (tofMatch.getSignal() - exp) * 1e-3; // time in ns wrt TF start
3243 auto bc = relativeTime_to_GlobalBC(tofSignal);
3244
3245 auto it = bcsMap.lower_bound(bc);
3246 if (it == bcsMap.end() || it->first > bc + maxGapBC) {
3247 bcsMap.emplace_hint(it, bc, 1);
3248 LOG(debug) << "adding dummy BC " << bc;
3249 }
3250 if (bc > maxBC) {
3251 maxBC = bc;
3252 }
3253 }
3254 }
3255 // make sure there is a globalBC exceeding the max encountered bc
3256 if ((--bcsMap.end())->first <= maxBC) {
3257 bcsMap.emplace_hint(bcsMap.end(), maxBC + 1, 1);
3258 }
3259 // renumber BCs
3260 int bcID = 0;
3261 for (auto& item : bcsMap) {
3262 item.second = bcID;
3263 bcID++;
3264 }
3265}
3266
3267std::uint64_t AODProducerWorkflowDPL::fillBCSlice(int (&slice)[2], double tmin, double tmax, const std::map<uint64_t, int>& bcsMap) const
3268{
3269 // for ambiguous tracks (no or multiple vertices) we store the BC slice corresponding to track time window used for track-vertex matching,
3270 // see VertexTrackMatcher::extractTracks creator method, i.e. central time estimated +- uncertainty defined as:
3271 // 1) for tracks having a gaussian time error: PVertexerParams.nSigmaTimeTrack * trackSigma + PVertexerParams.timeMarginTrackTime
3272 // 2) for tracks having time uncertainty in a fixed time interval (TPC,ITS,MFT..): half of the interval + PVertexerParams.timeMarginTrackTime
3273 // The track time in the TrackExtraInfo is stored in ns wrt the collision BC for unambigous tracks and wrt bcSlice[0] for ambiguous ones,
3274 // with convention for errors: trackSigma in case (1) and half of the time interval for case (2) above.
3275
3276 // find indices of widest slice of global BCs in the map compatible with provided BC range. bcsMap is guaranteed to be non-empty.
3277 // We also assume that tmax >= tmin.
3278
3279 uint64_t bcMin = relativeTime_to_GlobalBC(tmin), bcMax = relativeTime_to_GlobalBC(tmax);
3280
3281 /*
3282 // brute force way of searching bcs via direct binary search in the map
3283 auto lower = bcsMap.lower_bound(bcMin), upper = bcsMap.upper_bound(bcMax);
3284
3285 if (lower == bcsMap.end()) {
3286 --lower;
3287 }
3288 if (upper != lower) {
3289 --upper;
3290 }
3291 slice[0] = std::distance(bcsMap.begin(), lower);
3292 slice[1] = std::distance(bcsMap.begin(), upper);
3293 */
3294
3295 // faster way to search in bunch crossing via the accelerated bunch crossing lookup structure
3296 auto p = mBCLookup.lower_bound(bcMin);
3297 // assuming that bcMax will be >= bcMin and close to bcMin; we can find
3298 // the upper bound quickly by lineary iterating from p.first to the point where
3299 // the time becomes larger than bcMax.
3300 // (if this is not the case we could determine it with a similar call to mBCLookup)
3301 auto& bcvector = mBCLookup.getBCTimeVector();
3302 auto upperindex = p.first;
3303 while (upperindex < bcvector.size() && bcvector[upperindex] <= bcMax) {
3304 upperindex++;
3305 }
3306 if (upperindex != p.first) {
3307 upperindex--;
3308 }
3309 slice[0] = p.first;
3310 slice[1] = upperindex;
3311
3312 auto bcOfTimeRef = p.second - this->mStartIR.toLong();
3313 LOG(debug) << "BC slice t:" << tmin << " " << slice[0]
3314 << " t: " << tmax << " " << slice[1]
3315 << " bcref: " << bcOfTimeRef;
3316 return bcOfTimeRef;
3317}
3318
3319std::vector<uint8_t> AODProducerWorkflowDPL::fillBCFlags(const o2::globaltracking::RecoContainer& data, std::map<uint64_t, int>& bcsMap) const
3320{
3321 std::vector<uint8_t> flags(bcsMap.size());
3322
3323 // flag BCs belonging to UPC mode ITS ROFs
3324 auto bcIt = bcsMap.begin();
3325 auto itsrofs = data.getITSTracksROFRecords();
3328 for (auto& rof : itsrofs) {
3329 if (!rof.getFlag(o2::itsmft::ROFRecord::VtxUPCMode)) {
3330 continue;
3331 }
3332 uint64_t globalBC0 = rof.getBCData().toLong() + bROF, globalBC1 = globalBC0 + lROF - 1;
3333 // BCs are sorted, iterate until the start of ROF
3334 while (bcIt != bcsMap.end()) {
3335 if (bcIt->first < globalBC0) {
3336 ++bcIt;
3337 continue;
3338 }
3339 if (bcIt->first > globalBC1) {
3340 break;
3341 }
3342 flags[bcIt->second] |= o2::aod::bc::ITSUPCMode;
3343 ++bcIt;
3344 }
3345 }
3346 return flags;
3347}
3348
3350{
3351 LOGF(info, "aod producer dpl total timing: Cpu: %.3e Real: %.3e s in %d slots",
3352 mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1);
3353
3354 mStreamer.reset();
3355}
3356
3357DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, bool enableStrangenessTracking, bool useMC, bool CTPConfigPerRun, bool enableFITextra, bool enableTRDextra)
3358{
3359 auto dataRequest = std::make_shared<DataRequest>();
3360 dataRequest->inputs.emplace_back("ctpconfig", "CTP", "CTPCONFIG", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/Config", CTPConfigPerRun));
3361
3362 dataRequest->requestTracks(src, useMC);
3363 dataRequest->requestPrimaryVertices(useMC);
3364 if (src[GID::CTP]) {
3365 dataRequest->requestCTPDigits(useMC);
3366 }
3367 if (enableSV) {
3368 dataRequest->requestSecondaryVertices(useMC);
3369 }
3370 if (enableStrangenessTracking) {
3371 dataRequest->requestStrangeTracks(useMC);
3372 LOGF(info, "requestStrangeTracks Finish");
3373 }
3374 if (src[GID::ITS]) {
3375 dataRequest->requestClusters(GIndex::getSourcesMask("ITS"), false);
3376 }
3377 if (src[GID::TPC]) {
3378 dataRequest->requestClusters(GIndex::getSourcesMask("TPC"), false); // no need to ask for TOF clusters as they are requested with TOF tracks
3379 }
3380 if (src[GID::TOF]) {
3381 dataRequest->requestTOFClusters(useMC);
3382 }
3383 if (src[GID::PHS]) {
3384 dataRequest->requestPHOSCells(useMC);
3385 }
3386 if (src[GID::TRD]) {
3387 dataRequest->requestTRDTracklets(false);
3388 }
3389 if (src[GID::EMC]) {
3390 dataRequest->requestEMCALCells(useMC);
3391 }
3392 if (src[GID::CPV]) {
3393 dataRequest->requestCPVClusters(useMC);
3394 }
3395
3396 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(true, // orbitResetTime
3397 true, // GRPECS=true
3398 true, // GRPLHCIF
3399 true, // GRPMagField
3400 true, // askMatLUT
3402 dataRequest->inputs,
3403 true); // query only once all objects except mag.field
3404
3405 dataRequest->inputs.emplace_back("meanvtx", "GLO", "MEANVERTEX", 0, Lifetime::Condition, ccdbParamSpec("GLO/Calib/MeanVertex", {}, 1));
3406
3407 using namespace o2::aod;
3408 using namespace o2::aodproducer;
3409
3410 std::vector<OutputSpec> outputs{
3444 OutputSpec{"TFN", "TFNumber"},
3445 OutputSpec{"TFF", "TFFilename"},
3446 OutputSpec{"AMD", "AODMetadataKeys"},
3447 OutputSpec{"AMD", "AODMetadataVals"}};
3449 if (enableTRDextra) {
3450 outputs.push_back(OutputForTable<TRDsExtra>::spec());
3451 dataRequest->inputs.emplace_back("trdlocalgainfactors", "TRD", "LOCALGAINFACTORS", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/LocalGainFactor"));
3452 dataRequest->inputs.emplace_back("trdnoisemap", "TRD", "NOISEMAP", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/NoiseMapMCM"));
3453 dataRequest->inputs.emplace_back("trdgaincalib", "TRD", "CALGAIN", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/CalGain"));
3454 }
3455
3456 if (useMC) {
3457 outputs.insert(outputs.end(),
3458 {OutputForTable<McCollisions>::spec(),
3459 OutputForTable<HepMCXSections>::spec(),
3460 OutputForTable<HepMCPdfInfos>::spec(),
3461 OutputForTable<HepMCHeavyIons>::spec(),
3462 OutputForTable<McMFTTrackLabels>::spec(),
3463 OutputForTable<McFwdTrackLabels>::spec(),
3464 OutputForTable<StoredMcParticles_001>::spec(),
3465 OutputForTable<McTrackLabels>::spec(),
3466 OutputForTable<McCaloLabels_001>::spec(),
3467 // todo: use addTableToOuput helper?
3468 // currently the description is MCCOLLISLABEL, so
3469 // the name in AO2D would be O2mccollislabel
3470 // addTableToOutput<McCollisionLabels>(outputs);
3471 {OutputLabel{"McCollisionLabels"}, "AOD", "MCCOLLISIONLABEL", 0, Lifetime::Timeframe}});
3472 }
3473
3474 return DataProcessorSpec{
3475 "aod-producer-workflow",
3476 dataRequest->inputs,
3477 outputs,
3478 AlgorithmSpec{adaptFromTask<AODProducerWorkflowDPL>(src, dataRequest, ggRequest, enableSV, useMC, enableFITextra, enableTRDextra)},
3479 Options{
3480 ConfigParamSpec{"run-number", VariantType::Int64, -1L, {"The run-number. If left default we try to get it from DPL header."}},
3481 ConfigParamSpec{"aod-timeframe-id", VariantType::Int64, -1L, {"Set timeframe number"}},
3482 ConfigParamSpec{"fill-calo-cells", VariantType::Int, 1, {"Fill calo cells into cell table"}},
3483 ConfigParamSpec{"enable-truncation", VariantType::Int, 1, {"Truncation parameter: 1 -- on, != 1 -- off"}},
3484 ConfigParamSpec{"lpmp-prod-tag", VariantType::String, "", {"LPMProductionTag"}},
3485 ConfigParamSpec{"anchor-pass", VariantType::String, "", {"AnchorPassName"}},
3486 ConfigParamSpec{"anchor-prod", VariantType::String, "", {"AnchorProduction"}},
3487 ConfigParamSpec{"reco-pass", VariantType::String, "", {"RecoPassName"}},
3488 ConfigParamSpec{"created-by", VariantType::String, "", {"Who created this AO2D"}},
3489 ConfigParamSpec{"nthreads", VariantType::Int, std::max(1, int(std::thread::hardware_concurrency() / 2)), {"Number of threads"}},
3490 ConfigParamSpec{"reco-mctracks-only", VariantType::Int, 0, {"Store only reconstructed MC tracks and their mothers/daughters. 0 -- off, != 0 -- on"}},
3491 ConfigParamSpec{"ctpreadout-create", VariantType::Int, 0, {"Create CTP digits from detector readout and CTP inputs. !=1 -- off, 1 -- on"}},
3492 ConfigParamSpec{"emc-select-leading", VariantType::Bool, false, {"Flag to select if only the leading contributing particle for an EMCal cell should be stored"}},
3493 ConfigParamSpec{"propagate-tracks", VariantType::Bool, false, {"Propagate tracks (not used for secondary vertices) to IP"}},
3494 ConfigParamSpec{"propagate-tracks-max-xiu", VariantType::Float, 5.0f, {"Propagate tracks to IP if X_IU smaller than this value (and if propagate tracks enabled)"}},
3495 ConfigParamSpec{"hepmc-update", VariantType::String, "always", {"When to update HepMC Aux tables: always - force update, never - never update, all - if all keys are present, any - when any key is present (not valid yet)"}},
3496 ConfigParamSpec{"propagate-muons", VariantType::Bool, false, {"Propagate muons to IP"}},
3497 ConfigParamSpec{"thin-tracks", VariantType::Bool, false, {"Produce thinned track tables"}},
3498 ConfigParamSpec{"trackqc-keepglobaltracks", VariantType::Bool, false, {"Always keep TrackQA for global tracks"}},
3499 ConfigParamSpec{"trackqc-retainonlydedx", VariantType::Bool, false, {"Keep only dEdx information, zero out everything else"}},
3500 ConfigParamSpec{"trackqc-fraction", VariantType::Float, float(0.1), {"Fraction of tracks to QC"}},
3501 ConfigParamSpec{"trackqc-NTrCut", VariantType::Int64, 4L, {"Minimal length of the track - in amount of tracklets"}},
3502 ConfigParamSpec{"trackqc-tpc-dca", VariantType::Float, 3.f, {"Keep TPC standalone track with this DCAxy to the PV"}},
3503 ConfigParamSpec{"trackqc-tpc-cls", VariantType::Int, 80, {"Keep TPC standalone track with this #clusters"}},
3504 ConfigParamSpec{"trackqc-tpc-pt", VariantType::Float, 0.2f, {"Keep TPC standalone track with this pt"}},
3505 ConfigParamSpec{"with-streamers", VariantType::String, "", {"Bit-mask to steer writing of intermediate streamer files"}},
3506 ConfigParamSpec{"seed", VariantType::Int, 0, {"Set seed for random generator used for sampling (0 (default) means using a random_device)"}},
3507 ConfigParamSpec{"mc-signal-filt", VariantType::Bool, false, {"Enable usage of signal filtering (only for MC with embedding)"}}}};
3508}
3509
3510} // namespace o2::aodproducer
Class to refer to the reconstructed information.
Definition of the 32 Central Trigger System (CTS) Trigger Types defined in https://twiki....
General auxilliary methods.
definition of CTPConfiguration and related CTP structures
Wrapper container for different reconstructed object types.
Definition of the MCH cluster minimal structure.
Reconstructed MID track.
Base track model for the Barrel, params only, w/o covariance.
uint64_t exp(uint64_t base, uint8_t exp) noexcept
definition of CTPDigit, CTPInputDigit
std::ostringstream debug
int16_t charge
Definition RawEventData.h:5
uint64_t vertex
Definition RawEventData.h:9
uint64_t bc
Definition RawEventData.h:5
int16_t time
Definition RawEventData.h:4
Definition of the FIT RecPoints class.
Definition of the FV0 RecPoints class.
int32_t i
std::string getType()
Definition Utils.h:138
Header of the AggregatedRunInfo struct.
Global Forward Muon tracks.
Global index for barrel track: provides provenance (detectors combination), index in respective array...
Definition of the MCTrack class.
Definition of a container to keep Monte Carlo truth external to simulation objects.
Utility functions for MC particles.
Definition of the MCH ROFrame record.
Class to perform MFT MCH (and MID) matching.
Class to store the output of the matching to HMPID.
Class to perform TOF matching to global tracks.
Definition of the parameter class for the detector electronics.
Header to collect physics constants.
uint32_t j
Definition RawData.h:0
Definition of the FDD RecPoint class.
Definition of tools for track extrapolation.
Definition of the ITS track.
Definition of the MUON track.
Definition of the MCH track.
Definition of the MCH track parameters for internal use.
Result of refitting TPC-ITS matched track.
Extention of GlobalTrackID by flags relevant for verter-track association.
Referenc on track indices contributing to the vertex, with possibility chose tracks from specific sou...
Container class to store energy released in the ZDC.
Container class to store a TDC hit in a ZDC channel.
int nClusters
StringRef key
const auto & getBCPattern() const
void GetStartVertex(TVector3 &vertex) const
Definition MCTrack.h:326
void endOfStream(framework::EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj) final
std::pair< size_t, uint64_t > lower_bound(uint64_t timestamp) const
void init(std::map< uint64_t, int > const &bcs)
initialize this container (to be ready for lookup/search queries)
void clear()
clear/reset this container
std::vector< uint64_t > const & getBCTimeVector() const
return the sorted vector of increaing BC times
static float getAmplitude(const o2::emcal::Cell &cell)
static int16_t getLnAmplitude(const o2::emcal::Cell &)
static int8_t getTriggerBits(const o2::emcal::Cell &)
static int16_t getCellNumber(const o2::emcal::Cell &cell)
static int16_t getFastOrAbsID(const o2::emcal::Cell &)
static bool isTRU(const o2::emcal::Cell &cell)
static float getTimeStamp(const o2::emcal::Cell &cell)
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
static constexpr float MAX_SIN_PHI
Definition Propagator.h:72
static constexpr float MAX_STEP
Definition Propagator.h:73
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
Definition Propagator.h:178
void printStream(std::ostream &stream) const
static mask_t getSourcesMask(const std::string_view srcList)
VertexBase getMeanVertex(float z) const
int getEntriesOfSource(int s) const
Definition VtxTrackRef.h:62
int getFirstEntryOfSource(int s) const
Definition VtxTrackRef.h:55
Static class with identifiers, bitmasks and names for ALICE detectors.
Definition DetID.h:58
static constexpr ID ITS
Definition DetID.h:63
static constexpr ID MFT
Definition DetID.h:71
static constexpr ID TPC
Definition DetID.h:64
static constexpr ID EMC
Definition DetID.h:69
static constexpr ID TOF
Definition DetID.h:66
Handler for EMCAL event data.
void reset()
Reset containers with empty ranges.
void setCellData(CellRange cells, TriggerRange triggers)
Setting the data at cell level.
void setCellMCTruthContainer(const o2::dataformats::MCTruthContainer< o2::emcal::MCLabel > *mclabels)
Setting the pointer for the MCTruthContainer for cells.
InteractionRecord getInteractionRecordForEvent(int eventID) const
Get the interaction record for the given event.
int getNumberOfEvents() const
Get the number of events handled by the event handler.
void snapshot(const Output &spec, T const &object)
ConfigParamRegistry const & options()
Definition InitContext.h:33
decltype(auto) get(R binding, int part=0) const
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
ServiceRegistryRef services()
The services registry associated with this processing context.
static constexpr int NCellsA
Definition Geometry.h:52
o2::dataformats::GlobalFwdTrack MCHtoFwd(const o2::mch::TrackParam &mchTrack)
Converts mchTrack parameters to Forward coordinate system.
static bool extrapToZ(TrackParam &trackParam, double zEnd)
static void setField()
static bool extrapToVertex(TrackParam &trackParam, double xVtx, double yVtx, double zVtx, double errXVtx, double errYVtx)
Definition TrackExtrap.h:62
static bool extrapToVertexWithoutBranson(TrackParam &trackParam, double zVtx, double xUpstream=0., double yUpstream=0., std::optional< double > zUpstream=std::nullopt)
Definition TrackExtrap.h:74
track parameters for internal use
Definition TrackParam.h:34
Double_t getNonBendingCoor() const
return non bending coordinate (cm)
Definition TrackParam.h:51
Double_t getBendingCoor() const
return bending coordinate (cm)
Definition TrackParam.h:59
void setCellMCTruthContainer(const o2::dataformats::MCTruthContainer< o2::phos::MCLabel > *mclabels)
Setting the pointer for the MCTruthContainer for cells.
void setCellData(CellRange cells, TriggerRange triggers)
Setting the data at cell level.
void reset()
Reset containers with empty ranges.
InteractionRecord getInteractionRecordForEvent(int eventID) const
int getNumberOfEvents() const
MCTrack const * getTrack(o2::MCCompLabel const &) const
void releaseTracksForSourceAndEvent(int source, int event)
API to ask releasing tracks (freeing memory) for source + event.
std::vector< MCTrack > const & getTracks(int source, int event) const
variant returning all tracks for source and event at once
static void addInteractionBC(int bc, bool fromCollisonCotext=false)
Definition Utils.cxx:52
static constexpr ID Pion
Definition PID.h:96
Double_t getX() const
Definition TrackFwd.h:58
float getMPVdEdx(int iDet, bool defaultAvg=true) const
Definition CalGain.h:36
Simple noise status bit for each MCM of the TRD.
bool isTrackletFromNoisyMCM(const Tracklet64 &trklt) const
T getValue(int roc, int col, int row) const
void set(const std::string &s, int base=DefaultBase)
Definition EnumFlags.h:420
bool match(const std::vector< std::string > &queries, const char *pattern)
Definition dcs-ccdb.cxx:229
struct _cl_event * event
Definition glcorearb.h:2982
GLfloat GLfloat GLfloat alpha
Definition glcorearb.h:279
GLint GLenum GLint x
Definition glcorearb.h:403
GLenum src
Definition glcorearb.h:1767
GLint GLsizei count
Definition glcorearb.h:399
GLuint entry
Definition glcorearb.h:5735
GLint GLint GLsizei GLuint * counters
Definition glcorearb.h:3985
GLuint GLuint end
Definition glcorearb.h:469
const GLdouble * v
Definition glcorearb.h:832
GLdouble GLdouble right
Definition glcorearb.h:4077
GLdouble f
Definition glcorearb.h:310
GLuint GLuint GLfloat weight
Definition glcorearb.h:5477
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLsizei GLsizei GLchar * source
Definition glcorearb.h:798
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
GLenum GLsizei GLsizei GLint * values
Definition glcorearb.h:1576
GLboolean * data
Definition glcorearb.h:298
GLintptr offset
Definition glcorearb.h:660
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLfloat v0
Definition glcorearb.h:811
GLbitfield flags
Definition glcorearb.h:1570
GLboolean r
Definition glcorearb.h:1233
GLuint start
Definition glcorearb.h:469
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
constexpr std::array< float, 2 > trackQAScaledTOF
Definition DataTypes.h:137
constexpr std::array< float, 5 > trackQAScaleContP1
Definition DataTypes.h:134
uint8_t itsSharedClusterMap uint8_t
constexpr std::array< float, 5 > trackQAScaleContP0
Definition DataTypes.h:133
constexpr std::array< float, 5 > trackQAScaleGloP0
Definition DataTypes.h:135
constexpr std::array< float, 5 > trackQAScaleGloP1
Definition DataTypes.h:136
constexpr float trackQAScaleBins
Definition DataTypes.h:131
constexpr float trackQARefRadius
Definition DataTypes.h:130
bool updateHepMCHeavyIon(const HeavyIonCursor &cursor, int collisionID, short generatorID, o2::dataformats::MCEventHeader const &header, HepMCUpdate when=HepMCUpdate::anyKey)
short updateMCCollisions(const CollisionCursor &cursor, int bcId, float time, o2::dataformats::MCEventHeader const &header, short generatorId=0, int sourceId=0, unsigned int mask=0xFFFFFFF0)
bool updateHepMCPdfInfo(const PdfInfoCursor &cursor, int collisionID, short generatorID, o2::dataformats::MCEventHeader const &header, HepMCUpdate when=HepMCUpdate::anyKey)
uint32_t updateParticles(const ParticleCursor &cursor, int collisionID, std::vector< MCTrack > const &tracks, TrackToIndex &preselect, uint32_t offset=0, bool filter=false, bool background=false, uint32_t weightMask=0xFFFFFFF0, uint32_t momentumMask=0xFFFFFFF0, uint32_t positionMask=0xFFFFFFF0, bool signalFilter=false)
bool updateHepMCXSection(const XSectionCursor &cursor, int collisionID, short generatorID, o2::dataformats::MCEventHeader const &header, HepMCUpdate when=HepMCUpdate::anyKey)
framework::DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, bool enableST, bool useMC, bool CTPConfigPerRun, bool enableFITextra, bool enableTRDextra)
create a processor spec
void keepMCParticle(std::vector< std::vector< std::unordered_map< int, int > > > &store, int source, int event, int track, int value=1, bool useSigFilt=false)
void dimensionMCKeepStore(std::vector< std::vector< std::unordered_map< int, int > > > &store, int Nsources, int NEvents)
void clearMCKeepStore(std::vector< std::vector< std::unordered_map< int, int > > > &store)
constexpr int LHCMaxBunches
constexpr double LHCBunchSpacingNS
constexpr float Almost1
constexpr double MassPionCharged
Defining PrimaryVertex explicitly as messageable.
std::vector< ConfigParamSpec > ccdbParamSpec(std::string const &path, int runDependent, std::vector< CCDBMetadata > metadata={}, int qrate=0)
auto get(const std::byte *buffer, size_t=0)
Definition DataHeader.h:454
int angle2Sector(float phi)
Definition Utils.h:183
float sector2Angle(int sect)
Definition Utils.h:193
TrackParCovF TrackParCov
Definition Track.h:33
constexpr float MPVDEDXDEFAULT
default Most Probable Value of TRD dEdx
Definition Constants.h:84
constexpr uint32_t Cal
Definition Triggers.h:32
const int TDCSignal[NTDCChannels]
Definition Constants.h:181
constexpr int NTDCChannels
Definition Constants.h:90
constexpr int NChannels
Definition Constants.h:65
std::string fullVersion()
get full version information (official O2 release and git commit)
GPUReconstruction * rec
static OutputSpec const spec()
decltype(FFL(std::declval< cursor_t >())) cursor
const U & getTrack(int src, int id) const
GlobalIDSet getSingleDetectorRefs(GTrackID gidx) const
const o2::tpc::TrackTPC & getTPCTrack(GTrackID id) const
gsl::span< const o2::trd::CalibratedTracklet > getTRDCalibratedTracklets() const
gsl::span< const o2::trd::TriggerRecord > getTRDTriggerRecords() const
const o2::dataformats::TrackTPCITS & getTPCITSTrack(GTrackID gid) const
void collectData(o2::framework::ProcessingContext &pc, const DataRequest &request)
gsl::span< const o2::trd::Tracklet64 > getTRDTracklets() const
static bool downsampleTsallisCharged(float pt, float factorPt, float sqrts, float &weight, float rnd, float mass=0.13957)
Definition Tsallis.cxx:31
std::vector< o2::ctf::BufferType > vec
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
Cluster clu
std::uniform_int_distribution< unsigned long long > distr
std::random_device rd
std::array< uint16_t, 5 > pattern