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