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