57#include <unordered_set>
62#include "TStopwatch.h"
115constexpr float TanSector = 0.17632698f;
118bool outsideDriftVolume(
bool sideA,
float z,
float margin)
121 return sideA ? (
z < -margin ||
z > zLength + margin) : (
z > margin ||
z < -zLength - margin);
127 return trk.hasASideClustersOnly() ? 1 : (trk.hasCSideClustersOnly() ? -1 : 0);
134 CosmicsClusterCollectorSpec(std::shared_ptr<DataRequest> dr, std::shared_ptr<o2::base::GRPGeomRequest> gr,
bool useMC,
DetID::mask_t roadDets) : mDataRequest(dr), mGGCCDBRequest(gr), mRoadDets(roadDets), mUseMC(useMC) {}
152 int side(
float x,
float y)
const
154 const float orientation = isLine ? (
x - pcaX) * dirX + (
y - pcaY) * dirY : (pcaX - centerX) * (
y - centerY) - (pcaY - centerY) * (
x - centerX);
155 return orientation > 0.f ? 1 : -1;
157 bool accept(
float x,
float y)
const {
return sign == 0 ||
side(
x,
y) == sign; }
169 void fillTPCOccupancy(gsl::span<const unsigned int> occupancyMap);
170 float tpcOccupancy(
float timeTB,
bool after)
const;
171 void buildUsedMap(
const RecoContainer&
data, std::vector<std::pair<float, float>>& time0Windows);
172 void addTPCAttached(
const RecoContainer&
data,
const o2::tpc::TrackTPC& trk, std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const;
182 void addTPCCorridor(
const RecoContainer&
data,
const o2::tpc::TrackTPC& trk,
const CosmicTime& cosmicTime, std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const;
184 std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const;
185 void searchRow(
const o2::tpc::ClusterNativeAccess&
clusters,
int sector,
int row,
float y,
float z,
float snp,
float tgl,
float vertexTime,
float zTolerance, uint8_t flag,
186 float dxRow, std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const;
187 void addDebugRoadPoint(
int sector,
float x,
float y,
float z,
float snp,
float tgl,
int row,
float vertexTime,
int frameCode)
const;
188 struct ITSPattRequest {
193 void addITS(
const RecoContainer&
data,
GTrackID gid, uint8_t leg, std::vector<o2::dataformats::CosmicITSCluster>& out,
int icosm, std::vector<ITSPattRequest>& requests, std::unordered_set<int>& matched)
const;
194 void fillITSPatterns(
const RecoContainer&
data, std::vector<ITSPattRequest>& requests, std::vector<o2::dataformats::TrackCosmicsExtended>& cosmics)
const;
195 void addTOF(
const RecoContainer&
data,
GTrackID gid, uint8_t leg, std::vector<o2::dataformats::CosmicTOFCluster>& out, std::unordered_set<int>& matched)
const;
196 void addTRD(
const RecoContainer&
data,
GTrackID gid, uint8_t leg, std::vector<o2::dataformats::CosmicTRDTracklet>& out, std::unordered_set<int>& matched)
const;
197 std::pair<float, float> timeWindowMUS(
const CosmicTime& cosmicTime)
const;
198 bool predictOutward(
const o2::tpc::TrackTPC& leg,
const CosmicTime& cosmicTime,
int sector,
float x,
float&
y,
float&
z)
const;
199 void roadTOF(
const RecoContainer&
data,
const o2::tpc::TrackTPC*
const* legs,
const CosmicTime& cosmicTime,
int icosm, std::vector<o2::dataformats::CosmicTOFCluster>& out,
const std::unordered_set<int>& matched,
float& timeTOFMUS,
float& scoreTOFPair,
float& scoreTOFReversed)
const;
201 void roadTRD(
const RecoContainer&
data,
const o2::tpc::TrackTPC*
const* legs,
const CosmicTime& cosmicTime,
int icosm, std::vector<o2::dataformats::CosmicTRDTracklet>& out,
const std::unordered_set<int>& matched)
const;
202 void roadITS(
const RecoContainer&
data,
const o2::dataformats::TrackCosmics& cosm,
const CosmicTime& cosmicTime,
int legsSide,
int icosm, std::vector<o2::dataformats::CosmicITSCluster>& out, std::vector<ITSPattRequest>& requests,
203 const std::unordered_set<int>& matched)
const;
204 void cacheITSChipCentres();
206 void flagDuplicates(std::vector<o2::dataformats::TrackCosmicsExtended>& cosmics)
const;
209 std::shared_ptr<DataRequest> mDataRequest;
210 std::shared_ptr<o2::base::GRPGeomRequest> mGGCCDBRequest;
213 std::vector<bool> mUsed;
215 float mCorridor = 1.f;
216 float mMaxAbsTimeErr = 0.5f;
217 size_t mMaxCosmicsPerTF = 100;
219 float mRoadTOF = 5.f;
220 float mTOFFlightTol = 2.f;
221 float mTOFTimeErr = 0.1f;
222 float mRoadTRD = 5.f;
223 float mRoadITS = 1.5f;
224 std::vector<o2::math_utils::Point3D<float>> mITSChipCentres;
225 float mTPCTBinMUS = 0.2f;
226 std::vector<uint64_t> mTPCOccCumul;
227 float mTPCOccBinTB = 16.f;
228 int mTPCOccBinsPerOrbit = 1;
229 float mTPCOccTF = -1.f;
232 mutable bool mStaggeredWarned =
false;
233 mutable bool mNoDictWarned =
false;
234 mutable bool mTRDMismatchWarned =
false;
235 std::unique_ptr<o2::utils::TreeStreamRedirector> mDebugOut;
239 float mDbgTauC = 0.f;
242 std::vector<int> roadLeg;
243 std::vector<int> roadFrame;
244 std::vector<int> roadSector;
245 std::vector<int> roadRow;
246 std::vector<float> roadX;
247 std::vector<float> roadY;
248 std::vector<float> roadZ;
249 std::vector<float> roadZCos;
250 std::vector<float> roadGx;
251 std::vector<float> roadGy;
252 std::vector<float> roadSnp;
253 std::vector<float> roadTgl;
254 std::vector<int> tofLeg;
255 std::vector<int> tofChannel;
256 std::vector<int> tofFlags;
257 std::vector<double> tofTimeRaw;
258 std::vector<double> tofTime;
259 std::vector<float> tofTot;
260 std::vector<float> tofX;
261 std::vector<float> tofY;
262 std::vector<float> tofZ;
263 std::vector<float> tofGx;
264 std::vector<float> tofGy;
265 std::vector<int> trdLeg;
266 std::vector<int> trdLayer;
267 std::vector<float> trdX;
268 std::vector<float> trdY;
269 std::vector<float> trdZ;
270 std::vector<float> trdDy;
271 std::vector<float> trdDz;
272 std::vector<float> trdTrigMUS;
274 mutable std::vector<DebugCosmic> mDbgCosmics;
275 size_t mNCosmics = 0;
276 size_t mNClAttached = 0;
277 size_t mNClCorridor = 0;
286 mCorridor = ic.
options().
get<
float>(
"corridor-width");
287 mMaxAbsTimeErr = ic.
options().
get<
float>(
"max-abs-time-err");
288 mMaxCosmicsPerTF = std::max(0, ic.
options().
get<
int>(
"max-cosmics-per-tf"));
289 mRoadTOF = ic.
options().
get<
float>(
"tof-road-width");
290 mTOFFlightTol = ic.
options().
get<
float>(
"tof-flight-tolerance");
291 mTOFTimeErr = ic.
options().
get<
float>(
"tof-time-error");
292 mRoadTRD = ic.
options().
get<
float>(
"trd-road-width");
293 mRoadITS = ic.
options().
get<
float>(
"its-road-width");
296 const std::string
name = timesliceId == 0 ?
"cosmics_collector_debug.root" : fmt::format(
"cosmics_collector_debug_{}.root", timesliceId);
297 mDebugOut = std::make_unique<o2::utils::TreeStreamRedirector>(
name.c_str(),
"recreate");
306 updateTimeDependentParams(pc);
312 tfInfo.
vDrift = mCorrMap->getVDrift();
313 tfInfo.
t0 = mCorrMap->getT0();
315 tfInfo.
tpcOcc = mTPCOccTF;
317 std::vector<o2::dataformats::TrackCosmicsExtended> cosmicsOut;
319 const size_t nCosmics = std::min(cosmics.size(), mMaxCosmicsPerTF);
320 if (nCosmics < cosmics.size()) {
321 LOGP(warning,
"{} cosmics in TF {}, only the first {} are written (max-cosmics-per-tf)", cosmics.size(), tfID.
tfCounter, nCosmics);
326 std::vector<std::pair<float, float>> time0Windows;
327 for (
size_t ic = 0; ic < nCosmics; ic++) {
328 for (
const auto leg : {cosmics[ic].getRefBottom(), cosmics[ic].getRefTop()}) {
332 time0Windows.emplace_back(time0 - maxDistTB, time0 + maxDistTB);
336 buildUsedMap(recoData, time0Windows);
338 std::vector<ITSPattRequest> pattRequests;
339 std::unique_ptr<o2::gpu::GPUO2InterfaceRefit> tpcRefitter;
348 mDbgCosmics.assign(nCosmics, DebugCosmic{});
350 for (
size_t ic = 0; ic < nCosmics; ic++) {
351 const auto& cosm = cosmics[ic];
352 auto& out = cosmicsOut.emplace_back();
357 const GTrackID legs[2] = {cosm.getRefBottom(), cosm.getRefTop()};
359 std::vector<o2::dataformats::CosmicTPCCluster>* tpcCl[2] = {&out.clTPCBottom, &out.clTPCTop};
360 std::unordered_set<int> matchedITS;
361 std::unordered_set<int> matchedTOF;
362 std::unordered_set<int> matchedTRD;
363 for (uint8_t leg = 0; leg < 2; leg++) {
367 (leg == 0 ? out.tpcBottom : out.tpcTop) = *tpcLegs[leg];
370 addITS(recoData, refs[
GTrackID::ITS], leg, out.clITS, ic, pattRequests, matchedITS);
373 addTOF(recoData, refs[
GTrackID::TOF], leg, out.clTOF, matchedTOF);
379 addTRD(recoData, refs[
GTrackID::TRD], leg, out.trdTracklets, matchedTRD);
382 CosmicTime cosmicTime;
383 cosmicTime.tb = cosm.getTimeMUS().getTimeStamp() / mTPCTBinMUS;
384 cosmicTime.errTB = cosm.getTimeMUS().getTimeStampError() / mTPCTBinMUS;
385 cosmicTime.known = cosm.getTimeMUS().getTimeStampError() < mMaxAbsTimeErr;
389 if (mRoadDets[DetID::TOF]) {
390 roadTOF(recoData, tpcLegs, cosmicTime, ic, out.clTOF, matchedTOF, out.timeTOFMUS, out.scoreTOFPair, out.scoreTOFReversed);
393 polish(tpcLegs, out.timeTOFMUS, *tpcRefitter, out);
395 CosmicTime roadTime = cosmicTime;
396 if (out.hasTOFTime()) {
397 roadTime.tb = out.timeTOFMUS / mTPCTBinMUS;
398 roadTime.errTB = mTOFTimeErr / mTPCTBinMUS;
399 roadTime.known =
true;
401 mDbgTauC = roadTime.tb;
402 out.tpcOccBef = tpcOccupancy(roadTime.tb,
false);
403 out.tpcOccAft = tpcOccupancy(roadTime.tb,
true);
404 std::unordered_set<uint32_t> taken;
405 for (
int leg = 0; leg < 2; leg++) {
407 addTPCAttached(recoData, *tpcLegs[leg], *tpcCl[leg], taken);
408 mNClAttached += tpcCl[leg]->size();
411 for (
int leg = 0; leg < 2; leg++) {
413 const size_t nAttached = tpcCl[leg]->size();
415 addTPCCorridor(recoData, *tpcLegs[leg], roadTime, *tpcCl[leg], taken);
416 mNClCorridor += tpcCl[leg]->size() - nAttached;
419 if (mRoadDets[DetID::TRD]) {
420 roadTRD(recoData, tpcLegs, roadTime, ic, out.trdTracklets, matchedTRD);
422 if (mRoadDets[DetID::ITS]) {
425 if (tpcLegs[0] && tpcLegs[1] && legs[0].getSource() ==
GTrackID::TPC && legs[1].getSource() ==
GTrackID::TPC && tpcSide(*tpcLegs[0]) == tpcSide(*tpcLegs[1])) {
426 legsSide = tpcSide(*tpcLegs[0]);
428 roadITS(recoData, cosm, roadTime, legsSide, ic, out.clITS, pattRequests, matchedITS);
431 if (!pattRequests.empty()) {
432 fillITSPatterns(recoData, pattRequests, cosmicsOut);
434 flagDuplicates(cosmicsOut);
436 for (
size_t ic = 0; ic < cosmicsOut.size(); ic++) {
437 writeDebug(cosmicsOut[ic], ic);
440 mNCosmics += cosmicsOut.size();
441 LOGP(info,
"Collected clusters for {} cosmics in TF {}", cosmicsOut.size(), tfID.
tfCounter);
448void CosmicsClusterCollectorSpec::updateTimeDependentParams(
ProcessingContext& pc)
451 mCorrMap = &o2::gpu::TPCFastTransformPOD::get(pc.
inputs().
get<
const char*>(
"corrMap"));
454 if (mRoadDets[DetID::ITS] && mITSChipCentres.empty()) {
455 cacheITSChipCentres();
459void CosmicsClusterCollectorSpec::cacheITSChipCentres()
462 geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G));
463 mITSChipCentres.resize(geom->getNumberOfChips());
464 for (
int chip = 0; chip < geom->getNumberOfChips(); chip++) {
469void CosmicsClusterCollectorSpec::buildUsedMap(
const RecoContainer&
data, std::vector<std::pair<float, float>>& time0Windows)
472 std::sort(time0Windows.begin(), time0Windows.end());
473 std::vector<std::pair<float, float>> merged;
474 for (
const auto& window : time0Windows) {
475 if (!merged.empty() && window.first <= merged.back().second) {
476 merged.back().second = std::max(merged.back().second, window.second);
478 merged.push_back(window);
483 const auto refs =
data.getTPCTracksClusterRefs();
484 mUsed.assign(
clusters.nClustersTotal,
false);
485 for (
const auto& trk :
tracks) {
486 const float time0 = trk.getTime0();
487 const auto window = std::upper_bound(merged.begin(), merged.end(), time0, [](
float t,
const std::pair<float, float>&
w) { return t < w.first; });
488 if (window == merged.begin() || time0 > std::prev(window)->second) {
491 for (
int j = 0;
j < trk.getNClusterReferences();
j++) {
495 trk.getClusterReference(refs,
j, sector,
row, clIdx);
496 mUsed[
clusters.clusterOffset[sector][
row] + clIdx] =
true;
501void CosmicsClusterCollectorSpec::fillTPCOccupancy(gsl::span<const unsigned int> occupancyMap)
505 mTPCOccCumul.clear();
506 mTPCOccTF = occupancyMap.empty() ? -1.f : occupancyMap[0];
507 if (occupancyMap.size() < 3 || (occupancyMap[1] >> 16) == 0) {
510 mTPCOccBinTB = occupancyMap[1] >> 16;
511 mTPCOccBinsPerOrbit = std::max(1,
static_cast<int>(o2::constants::lhc::LHCMaxBunches / 8 / mTPCOccBinTB));
512 mTPCOccCumul.resize(occupancyMap.size() - 1, 0);
513 for (
size_t bin = 2; bin < occupancyMap.size(); bin++) {
514 mTPCOccCumul[bin - 1] = mTPCOccCumul[bin - 2] + occupancyMap[bin];
518float CosmicsClusterCollectorSpec::tpcOccupancy(
float timeTB,
bool after)
const
522 if (mTPCOccCumul.empty()) {
525 const int nBins =
static_cast<int>(mTPCOccCumul.size()) - 1;
526 const int bin =
static_cast<int>(std::floor(timeTB / mTPCOccBinTB));
527 const int first = after ? bin : bin - mTPCOccBinsPerOrbit;
528 const int last = after ? bin + mTPCOccBinsPerOrbit : bin;
529 if (first < 0 || last > nBins) {
532 return static_cast<float>(mTPCOccCumul[
last] - mTPCOccCumul[
first]);
535void CosmicsClusterCollectorSpec::addTPCAttached(
const RecoContainer&
data,
const o2::tpc::TrackTPC& trk, std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const
538 const auto refs =
data.getTPCTracksClusterRefs();
539 for (
int j = 0;
j < trk.getNClusterReferences();
j++) {
543 trk.getClusterReference(refs,
j, sector,
row, clIdx);
544 if (!taken.insert(
clusters.clusterOffset[sector][
row] + clIdx).second) {
547 auto& cl = out.emplace_back();
557 if (std::abs(inner.getCurvature(bz)) < 1e-5f) {
559 const auto point = inner.getXYZGlo();
560 const float phi = inner.getPhi();
561 dirX = std::cos(phi);
562 dirY = std::sin(phi);
563 const float proj = point.X() * dirX + point.Y() * dirY;
564 pcaX = point.X() - proj * dirX;
565 pcaY = point.Y() - proj * dirY;
568 float sinAlpha = 0.f;
569 float cosAlpha = 0.f;
570 inner.getCircleParams(bz, circle, sinAlpha, cosAlpha);
573 const float centerDist = std::sqrt(centerX * centerX + centerY * centerY);
574 if (centerDist < 1e-3f) {
578 pcaX = centerX * (1.f - circle.
rC / centerDist);
579 pcaY = centerY * (1.f - circle.
rC / centerDist);
583 const auto pointIn = inner.getXYZGlo();
584 const auto pointOut = outer.getXYZGlo();
585 const float distIn2 = (pointIn.X() - pcaX) * (pointIn.X() - pcaX) + (pointIn.Y() - pcaY) * (pointIn.Y() - pcaY);
586 const float distOut2 = (pointOut.X() - pcaX) * (pointOut.X() - pcaX) + (pointOut.Y() - pcaY) * (pointOut.Y() - pcaY);
587 const int sideIn =
side(pointIn.X(), pointIn.Y());
588 const int sideOut =
side(pointOut.X(), pointOut.Y());
589 constexpr float MinDist2 = 10.f * 10.f;
590 if (sideIn == sideOut) {
592 }
else if (std::min(distIn2, distOut2) < MinDist2) {
593 sign = distIn2 > distOut2 ? sideIn : sideOut;
599void CosmicsClusterCollectorSpec::addTPCCorridor(
const RecoContainer&
data,
const o2::tpc::TrackTPC& trk,
const CosmicTime& cosmicTime, std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const
603 const float vDrift = mCorrMap->getVDrift();
605 const float time0Leg = trk.getTime0();
606 const int legSide = tpcSide(trk);
611 frames[nFrames++] = {time0Leg, 0.f, 0.f, 0, 2 * NSectorsA, 0};
613 frames[nFrames++] = {time0Leg, 0.f, 0.f, legSide > 0 ? 0 : NSectorsA, legSide > 0 ? NSectorsA : 2 * NSectorsA, 0};
614 if (cosmicTime.known) {
615 frames[nFrames++] = {cosmicTime.tb, legSide * (cosmicTime.tb - time0Leg) * vDrift, cosmicTime.errTB * vDrift,
616 legSide > 0 ? NSectorsA : 0, legSide > 0 ? 2 * NSectorsA : NSectorsA,
o2::dataformats::CosmicTPCCluster::AbsTime};
622 branch.init(refPar[0], refPar[1], mBz);
623 const auto pointIn = refPar[0].getXYZGlo();
624 const auto pointOut = refPar[1].getXYZGlo();
625 const float rIn = std::hypot(pointIn.X(), pointIn.Y());
626 const float rOut = std::hypot(pointOut.X(), pointOut.Y());
629 for (
int iFrame = 0; iFrame < nFrames; iFrame++) {
630 const auto& frame = frames[iFrame];
631 for (
int sector = frame.sectorMin; sector < frame.sectorMax; sector++) {
633 const float sinAlpha = std::sin(
alpha);
634 const float cosAlpha = std::cos(
alpha);
635 const bool sideA = sector < NSectorsA;
636 for (
int iPar = 0; iPar < 2; iPar++) {
637 auto par = refPar[iPar];
638 par.setZ(
par.getZ() + frame.dz);
645 for (
int row = 0;
row < o2::tpc::constants::MAXGLOBALPADROW;
row++) {
647 if ((xRow < rMid) != (iPar == 0)) {
651 if (!parRow.propagateParamTo(xRow, mBz)) {
655 constexpr float CoarseMargin = 10.f;
656 if (std::abs(parRow.getY()) > xRow * TanSector + mCorridor + CoarseMargin || outsideDriftVolume(sideA, parRow.getZ(), mCorridor + frame.zTolerance + CoarseMargin)) {
661 const float zInside = sideA ? std::clamp(parRow.getZ(), 0.f, zLength) :
std::
clamp(parRow.getZ(), -zLength, 0.f);
662 mCorrMap->InverseTransformYZtoX(sector,
row, parRow.getY(), zInside, xReal);
663 if (!parRow.propagateParamTo(xReal, mBz)) {
666 const float y = parRow.getY();
667 const float z = parRow.getZ();
668 if (std::abs(
y) > xRow * TanSector + mCorridor) {
671 if (outsideDriftVolume(sideA,
z, mCorridor + frame.zTolerance)) {
674 if (!branch.accept(xRow * cosAlpha -
y * sinAlpha, xRow * sinAlpha +
y * cosAlpha)) {
678 addDebugRoadPoint(sector, xReal,
y,
z, parRow.getSnp(), parRow.getTgl(),
row, frame.vertexTime, frame.flag != 0);
680 searchRow(
clusters, sector,
row,
y,
z, parRow.getSnp(), parRow.getTgl(), frame.vertexTime, frame.zTolerance, frame.flag, 0.f, out, taken);
687 const bool splitAtRMid =
rOut >
rIn;
688 for (
int iPar = 0; iPar < (splitAtRMid ? 2 : 1); iPar++) {
689 auto par = refPar[iPar];
690 par.setZ(
par.getZ() + frame.dz);
691 walkLowAngleRoad(
clusters, par, iPar == 0, splitAtRMid ? rMid :
std::numeric_limits<float>::
max(), branch, frame, out, taken);
697 const RoadFrame& frame, std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const
700 constexpr float CosSector = 0.98480775f;
701 constexpr float Step = 0.5f;
702 constexpr float MaxPath = 600.f;
703 constexpr float MaxEntryPath = 20.f;
704 constexpr float MinSnp = 0.8f;
705 constexpr float XMargin = 10.f;
706 constexpr int NRows = o2::tpc::constants::MAXGLOBALPADROW;
710 std::array<float, NSectorsA> sinSector{};
711 std::array<float, NSectorsA> cosSector{};
712 for (
int sector = 0; sector < NSectorsA; sector++) {
714 sinSector[sector] = std::sin(
alpha);
715 cosSector[sector] = std::cos(
alpha);
718 bool startInside =
false;
721 if (direction == 1) {
724 bool entered =
direction == 1 && startInside;
726 for (
float path = direction == 0 ? 0.f : Step;
path < MaxPath;
path += Step) {
728 if (
path > 0.f && (!
par.rotateParam(
par.getPhi()) || !
par.propagateParamTo(
par.getX() + Step, mBz))) {
731 const auto pos =
par.getXYZGlo();
732 const float r = std::hypot(
pos.X(),
pos.Y());
733 if (
r > rHigh || std::abs(
pos.Z()) > zLength + mCorridor + frame.zTolerance) {
738 if (
r < rLow || (
r < rMid) != innerPart || !branch.accept(
pos.X(),
pos.Y())) {
739 if (entered ||
path > MaxEntryPath) {
745 startInside = startInside ||
path == 0.f;
746 const float phiDir =
par.getPhi();
749 const int sectorInSide = (sectorPos +
dSector + NSectorsA) % NSectorsA;
750 for (
int sector = sectorInSide; sector < 2 * NSectorsA; sector += NSectorsA) {
751 if (sector < frame.sectorMin || sector >= frame.sectorMax) {
754 const bool sideA = sector < NSectorsA;
755 if (outsideDriftVolume(sideA,
pos.Z(), mCorridor + frame.zTolerance)) {
759 const float sinAlpha = sinSector[sectorInSide];
760 const float cosAlpha = cosSector[sectorInSide];
761 const float x =
pos.X() * cosAlpha +
pos.Y() * sinAlpha;
762 const float y = -
pos.X() * sinAlpha +
pos.Y() * cosAlpha;
763 float snp = std::sin(phiDir -
alpha);
764 float tgl =
par.getTgl();
765 if (std::cos(phiDir -
alpha) < 0.f) {
769 if (std::abs(snp) < MinSnp || std::abs(
y) >
x * TanSector + mCorridor) {
772 const float zInside = sideA ? std::clamp(
pos.Z(), 0.f, zLength) :
std::
clamp(
pos.Z(), -zLength, 0.f);
776 while (rowFirst < rowEnd) {
777 const int rowMid = (rowFirst + rowEnd) / 2;
779 rowFirst = rowMid + 1;
786 mCorrMap->InverseTransformYZtoX(sector,
row,
y, zInside, xReal);
787 const float dxRow = xReal -
x;
788 if (std::abs(dxRow) > mCorridor) {
792 addDebugRoadPoint(sector,
x,
y,
pos.Z(), snp, tgl,
row, frame.vertexTime, 2 + (frame.flag != 0));
794 searchRow(
clusters, sector,
row,
y,
pos.Z(), snp, tgl, frame.vertexTime, frame.zTolerance, frame.flag, dxRow, out, taken);
802void CosmicsClusterCollectorSpec::searchRow(
const o2::tpc::ClusterNativeAccess&
clusters,
int sector,
int row,
float y,
float z,
float snp,
float tgl,
float vertexTime,
float zTolerance, uint8_t flag,
803 float dxRow, std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const
807 const float vDrift = mCorrMap->getVDrift();
808 const float t0 = mCorrMap->getT0();
811 float yNominal = 0.f;
812 float zNominal = 0.f;
813 mCorrMap->InverseTransformYZtoNominalYZ(sector,
row,
y, zInside, yNominal, zNominal);
814 zNominal +=
z - zInside;
816 float driftLengthPred = 0.f;
818 const float timePred = driftLengthPred / vDrift +
t0 + vertexTime;
821 const float cosPhi = std::sqrt((1.f - snp) * (1.f + snp));
822 const float cosPhiWindow = std::max(cosPhi, 0.1f);
823 const float norm = 1.f / std::sqrt(1.f + tgl * tgl);
824 const float dirX = cosPhi *
norm;
825 const float dirY = snp *
norm;
826 const float dirZ = tgl *
norm;
827 const float corridor2 = mCorridor * mCorridor;
829 const float windowTime = (mCorridor * std::sqrt(cosPhiWindow * cosPhiWindow + tgl * tgl) / cosPhiWindow + zTolerance) / vDrift;
830 const auto* rowClusters =
clusters.clusters[sector][
row];
831 const uint32_t rowOffset =
clusters.clusterOffset[sector][
row];
832 for (uint32_t k = 0; k <
clusters.nClusters[sector][
row]; k++) {
833 const auto&
c = rowClusters[k];
834 const float time =
c.getTime();
835 const float pad =
c.getPad();
836 if (std::abs(
time - timePred) > windowTime || std::abs(pad - padPred) > windowPad) {
839 float yCluster = 0.f;
840 float zCluster = 0.f;
842 const float dy = yCluster - yNominal;
843 float dz = zCluster - zNominal;
844 if (zTolerance > 0.f) {
845 dz = std::abs(dz) > zTolerance ? dz - std::copysign(zTolerance, dz) : 0.f;
847 const float proj = dxRow * dirX + dy * dirY + dz * dirZ;
848 if (dxRow * dxRow + dy * dy + dz * dz - proj * proj > corridor2) {
851 if (!taken.insert(rowOffset + k).second) {
854 auto& cl = out.emplace_back();
862void CosmicsClusterCollectorSpec::addDebugRoadPoint(
int sector,
float x,
float y,
float z,
float snp,
float tgl,
int row,
float vertexTime,
int frameCode)
const
866 const float sinAlpha = std::sin(
alpha);
867 const float cosAlpha = std::cos(
alpha);
869 auto& dbg = mDbgCosmics[mDbgCosmic];
870 dbg.roadLeg.push_back(mDbgLeg);
871 dbg.roadFrame.push_back(frameCode);
872 dbg.roadSector.push_back(sector);
873 dbg.roadRow.push_back(
row);
874 dbg.roadX.push_back(
x);
875 dbg.roadY.push_back(
y);
876 dbg.roadZ.push_back(
z);
877 dbg.roadZCos.push_back(
z + (sideA ? 1.f : -1.f) * (mDbgTauC - vertexTime) * mCorrMap->getVDrift());
878 dbg.roadGx.push_back(
x * cosAlpha -
y * sinAlpha);
879 dbg.roadGy.push_back(
x * sinAlpha +
y * cosAlpha);
880 dbg.roadSnp.push_back(snp);
881 dbg.roadTgl.push_back(tgl);
884void CosmicsClusterCollectorSpec::addITS(
const RecoContainer&
data,
GTrackID gid, uint8_t leg, std::vector<o2::dataformats::CosmicITSCluster>& out,
int icosm, std::vector<ITSPattRequest>& requests, std::unordered_set<int>& matched)
const
889 if (
data.getITSPerLayer()) {
890 if (!mStaggeredWarned) {
891 LOGP(warning,
"Staggered ITS clusters are not supported, ITS clusters of cosmics are not stored");
892 mStaggeredWarned =
true;
896 const auto& trk =
data.getITSTrack(gid);
897 const auto refs =
data.getITSTracksClusterRefs();
899 const auto rofs =
data.getITSClustersROFRecords();
900 for (
int i = 0;
i < trk.getNumberOfClusters();
i++) {
901 const int idx = refs[trk.getFirstClusterEntry() +
i];
903 auto& cl = out.emplace_back();
904 cl.chipID =
c.getSensorID();
907 cl.pattID =
c.getPatternID();
912 requests.push_back({icosm,
int(out.size()) - 1,
idx});
914 auto rof = std::upper_bound(rofs.begin(), rofs.end(), idx, [](
int v,
const o2::itsmft::ROFRecord&
r) { return v < r.getFirstEntry(); });
915 if (rof != rofs.begin()) {
916 cl.rofBC = std::prev(rof)->getBCData().differenceInBC(mTFStart);
921void CosmicsClusterCollectorSpec::addTOF(
const RecoContainer&
data,
GTrackID gid, uint8_t leg, std::vector<o2::dataformats::CosmicTOFCluster>& out, std::unordered_set<int>& matched)
const
923 const auto&
c =
data.getTOFClusters()[gid.getIndex()];
924 auto& cl = out.emplace_back();
925 cl.timeRaw =
c.getTimeRaw();
927 cl.channel =
c.getMainContributingChannel();
930 matched.insert(gid.getIndex());
933std::pair<float, float> CosmicsClusterCollectorSpec::timeWindowMUS(
const CosmicTime& cosmicTime)
const
936 const float timeMUS = cosmicTime.tb * mTPCTBinMUS;
937 const float errMUS = cosmicTime.errTB * mTPCTBinMUS;
938 const float halfWidth = cosmicTime.known ? 5.f * errMUS + 0.2f : errMUS;
939 return {timeMUS - halfWidth, timeMUS + halfWidth};
942bool CosmicsClusterCollectorSpec::predictOutward(
const o2::tpc::TrackTPC& leg,
const CosmicTime& cosmicTime,
int sector,
float x,
float&
y,
float&
z)
const
951 z =
par.getZ() + tpcSide(leg) * (cosmicTime.tb - leg.getTime0()) * mCorrMap->getVDrift();
955void CosmicsClusterCollectorSpec::roadTOF(
const RecoContainer&
data,
const o2::tpc::TrackTPC*
const* legs,
const CosmicTime& cosmicTime,
int icosm, std::vector<o2::dataformats::CosmicTOFCluster>& out,
const std::unordered_set<int>& matched,
float& timeTOFMUS,
float& scoreTOFPair,
float& scoreTOFReversed)
const
962 constexpr float MaxFlightMUS = 0.1f;
963 constexpr float CmPerNS = 29.9792458f;
964 const auto window = timeWindowMUS(cosmicTime);
965 const float zTimeTol = 0.5f * (window.second - window.first) / mTPCTBinMUS * mCorrMap->getVDrift();
966 const float vDriftPerMUS = mCorrMap->getVDrift() / mTPCTBinMUS;
967 const float cosmicTimeMUS = cosmicTime.tb * mTPCTBinMUS;
968 int legSide[2] = {0, 0};
969 float curvature = 0.f;
971 for (
int leg = 0; leg < 2; leg++) {
973 legSide[leg] = tpcSide(*legs[leg]);
974 curvature += std::abs(legs[leg]->getCurvature(mBz));
978 curvature = nLegs ? curvature / nLegs : 0.f;
984 float dzAtCosmicTime;
989 std::vector<Candidate> candidates[2];
991 int best[2] = {-1, -1};
992 float bestScore[2] = {1.f, 1.f};
995 const float timeMUS =
c.getTime() * 1e-6f;
996 if (timeMUS < window.first - MaxFlightMUS || timeMUS > window.second + MaxFlightMUS) {
999 const bool isMatched = matched.count(
i) > 0;
1001 const float sinAlpha = std::sin(
alpha);
1002 const float cosAlpha = std::cos(
alpha);
1003 for (
int leg = 0; leg < 2; leg++) {
1006 if (!legs[leg] || !predictOutward(*legs[leg], cosmicTime,
c.getSector(),
c.getX(),
y,
z)) {
1009 const float normY = (
c.getY() -
y) / mRoadTOF;
1010 const float normZ = (
c.getZ() -
z) / (mRoadTOF + zTimeTol);
1011 const float score = std::max(normY * normY, normZ * normZ);
1015 if (!isMatched && score < bestScore[leg]) {
1016 bestScore[leg] = score;
1019 candidates[leg].push_back(Candidate{
i, isMatched,
c.getTime() * 1e-3,
c.getY() -
y,
c.getZ() -
z,
c.getX() * cosAlpha -
c.getY() * sinAlpha,
1020 c.getX() * sinAlpha +
c.getY() * cosAlpha,
c.getZ()});
1023 float bestPairScore = -1.f;
1024 float bestReversedScore = -1.f;
1025 int bestPair[2] = {-1, -1};
1026 for (
const auto& c0 : candidates[0]) {
1027 for (
const auto& c1 : candidates[1]) {
1028 if (c0.index == c1.index) {
1032 const auto&
top = c0.gy > c1.gy ? c0 : c1;
1033 const auto&
bottom = c0.gy > c1.gy ? c1 : c0;
1036 const float halfAngleSin = 0.5f * curvature * chordXY;
1037 const float arcXY = halfAngleSin > 1e-4f && halfAngleSin < 1.f ? 2.f * std::asin(halfAngleSin) / curvature : chordXY;
1039 const float timeDiff = float(
top.timeNS -
bottom.timeNS);
1040 const float flightDev = timeDiff +
length / CmPerNS;
1041 const float reversedDev = timeDiff -
length / CmPerNS;
1042 const bool reversed = std::abs(flightDev) > mTOFFlightTol;
1043 if (reversed && std::abs(reversedDev) > mTOFFlightTol) {
1046 const double pairTimeNS = 0.5 * (c0.timeNS + c1.timeNS);
1047 const float shiftMUS = float(pairTimeNS * 1e-3) - cosmicTimeMUS;
1048 const float dz0 = c0.dzAtCosmicTime - legSide[0] * shiftMUS * vDriftPerMUS;
1049 const float dz1 = c1.dzAtCosmicTime - legSide[1] * shiftMUS * vDriftPerMUS;
1050 if (std::abs(dz0) > mRoadTOF || std::abs(dz1) > mRoadTOF) {
1053 const float timeDev = reversed ? reversedDev : flightDev;
1054 const float score = (c0.dy * c0.dy + c1.dy * c1.dy + dz0 * dz0 + dz1 * dz1) / (mRoadTOF * mRoadTOF) + timeDev * timeDev / (mTOFFlightTol * mTOFFlightTol);
1056 if (bestReversedScore < 0.f || score < bestReversedScore) {
1057 bestReversedScore = score;
1061 if (bestPairScore < 0.f || score < bestPairScore) {
1062 bestPairScore = score;
1063 bestPair[0] = c0.index;
1064 bestPair[1] = c1.index;
1065 timeTOFMUS = float(pairTimeNS * 1e-3);
1069 scoreTOFPair = bestPairScore;
1070 scoreTOFReversed = bestReversedScore;
1072 if (bestPairScore >= 0.f) {
1073 best[0] = bestPair[0];
1074 best[1] = bestPair[1];
1076 }
else if (best[0] >= 0 && best[0] == best[1]) {
1077 best[bestScore[0] <= bestScore[1] ? 1 : 0] = -1;
1079 for (
int leg = 0; leg < 2; leg++) {
1080 if (best[leg] < 0) {
1084 if (matched.count(best[leg])) {
1085 for (
auto& cl : out) {
1086 if (cl.leg == leg && cl.channel ==
c.getMainContributingChannel() && cl.timeRaw ==
c.getTimeRaw()) {
1091 auto& dbg = mDbgCosmics[icosm];
1092 for (
size_t j = 0;
j < dbg.tofFlags.size();
j++) {
1093 if (dbg.tofLeg[
j] == leg && dbg.tofChannel[
j] ==
c.getMainContributingChannel() && dbg.tofTimeRaw[
j] ==
c.getTimeRaw()) {
1100 auto& cl = out.emplace_back();
1101 cl.timeRaw =
c.getTimeRaw();
1102 cl.tot =
c.getTot();
1103 cl.channel =
c.getMainContributingChannel();
1107 writeDebugTOF(
c, icosm, leg,
flags);
1119 constexpr int ELossGain = 1;
1120 constexpr int ELossLoss = -1;
1123 const float timeTB = timeMUS / mTPCTBinMUS;
1125 bottom.setPID(o2::track::PID::Muon,
true);
1126 bottom.resetCovariance();
1127 if (std::abs(mBz) <= 0.01f) {
1136 if (!prop->propagateToDCABxByBz(
origin,
bottom, matchParams.maxStep, matchParams.matCorr,
nullptr,
nullptr, ELossGain)) {
1140 top.setPID(o2::track::PID::Muon,
true);
1144 if (!
top.rotate(
bottom.getAlpha()) || !prop->PropagateToXBxByBz(
top,
bottom.getX(), matchParams.maxSnp, matchParams.maxStep, matchParams.matCorr,
nullptr, ELossLoss)) {
1147 o2::track::TrackParCov::MatrixDSym5 cov5;
1148 const float chi2Match =
bottom.getPredictedChi2(
top, cov5);
1156void CosmicsClusterCollectorSpec::roadTRD(
const RecoContainer&
data,
const o2::tpc::TrackTPC*
const* legs,
const CosmicTime& cosmicTime,
int icosm, std::vector<o2::dataformats::CosmicTRDTracklet>& out,
const std::unordered_set<int>& matched)
const
1159 constexpr float ReadoutWindowMUS = 3.f;
1160 constexpr float PadLength = 10.f;
1161 constexpr int NLayers = o2::trd::constants::NLAYER;
1162 const auto window = timeWindowMUS(cosmicTime);
1163 const float zTimeTol = 0.5f * (window.second - window.first) / mTPCTBinMUS * mCorrMap->getVDrift();
1165 const auto calibrated =
data.getTRDCalibratedTracklets();
1166 if (calibrated.size() !=
tracklets.size()) {
1167 if (!mTRDMismatchWarned) {
1168 LOGP(warning,
"{} calibrated vs {} raw TRD tracklets: TRD road of cosmics skipped", calibrated.size(),
tracklets.size());
1169 mTRDMismatchWarned =
true;
1178 Candidate
best[2][NLayers];
1179 for (
const auto& trig :
data.getTRDTriggerRecords()) {
1180 const int trigBC = trig.getBCData().differenceInBC(mTFStart);
1181 const float trigMUS = trigBC * o2::constants::lhc::LHCBunchSpacingMUS;
1182 if (trigMUS < window.first - ReadoutWindowMUS || trigMUS > window.second) {
1185 for (
int it = trig.getFirstTracklet(); it < trig.getFirstTracklet() + trig.getNumberOfTracklets(); it++) {
1186 if (matched.count(it)) {
1189 const int detector =
tracklets[it].getDetector();
1190 const int sector = detector / o2::trd::constants::NCHAMBERPERSEC;
1191 const int layer = detector % NLayers;
1192 const auto& point = calibrated[it];
1193 for (
int leg = 0; leg < 2; leg++) {
1196 if (!legs[leg] || !predictOutward(*legs[leg], cosmicTime, sector, point.getX(),
y,
z)) {
1199 const float normY = (point.getY() -
y) / mRoadTRD;
1200 const float normZ = (point.getZ() -
z) / (mRoadTRD + PadLength + zTimeTol);
1201 const float score = std::max(normY * normY, normZ * normZ);
1202 if (score < best[leg][
layer].score) {
1208 for (
int leg = 0; leg < 2; leg++) {
1211 if (cand.tracklet < 0) {
1214 auto& tr = out.emplace_back();
1215 tr.word =
tracklets[cand.tracklet].getTrackletWord();
1216 tr.trigBC = cand.trigBC;
1221 const auto& point = calibrated[cand.tracklet];
1222 const int sector =
tracklets[cand.tracklet].getDetector() / o2::trd::constants::NCHAMBERPERSEC;
1225 predictOutward(*legs[leg], cosmicTime, sector, point.getX(),
y,
z);
1226 auto& dbg = mDbgCosmics[icosm];
1227 dbg.trdLeg.push_back(leg);
1228 dbg.trdLayer.push_back(
layer);
1229 dbg.trdX.push_back(point.getX());
1230 dbg.trdY.push_back(point.getY());
1231 dbg.trdZ.push_back(point.getZ());
1232 dbg.trdDy.push_back(point.getY() -
y);
1233 dbg.trdDz.push_back(point.getZ() -
z);
1234 dbg.trdTrigMUS.push_back(cand.trigBC *
float(o2::constants::lhc::LHCBunchSpacingMUS));
1240void CosmicsClusterCollectorSpec::roadITS(
const RecoContainer&
data,
const o2::dataformats::TrackCosmics& cosm,
const CosmicTime& cosmicTime,
int legsSide,
int icosm, std::vector<o2::dataformats::CosmicITSCluster>& out,
1241 std::vector<ITSPattRequest>& requests,
const std::unordered_set<int>& matched)
const
1243 if (
data.getITSPerLayer() || mITSChipCentres.empty()) {
1247 constexpr float MaxRadius = 45.f;
1248 constexpr float ChipHalfDiag = 1.7f;
1250 if (!
par.rotateParam(
par.getPhi())) {
1253 std::vector<o2::math_utils::Point3D<float>> points;
1254 for (
float x = -MaxRadius - 5.f;
x <= MaxRadius + 5.f;
x += 1.f) {
1256 const auto point =
par.getXYZGloAt(
x, mBz, ok);
1258 points.push_back(point);
1261 if (points.size() < 2) {
1265 auto closest = [&points](
float x,
float y,
float& dist2,
float& zTraj) {
1267 for (
size_t i = 0;
i + 1 < points.size();
i++) {
1268 const float segX = points[
i + 1].X() - points[
i].X();
1269 const float segY = points[
i + 1].Y() - points[
i].Y();
1270 const float len2 = segX * segX + segY * segY;
1271 const float frac = len2 > 0.f ? std::clamp(((
x - points[
i].X()) * segX + (
y - points[
i].Y()) * segY) / len2, 0.f, 1.f) : 0.f;
1272 const float dx =
x - (points[
i].X() + frac * segX);
1273 const float dy =
y - (points[
i].Y() + frac * segY);
1274 if (dx * dx + dy * dy < dist2) {
1275 dist2 = dx * dx + dy * dy;
1276 zTraj = points[
i].Z() + frac * (points[
i + 1].Z() - points[
i].Z());
1280 float minR2 = 1e10f;
1282 for (
const auto& point : points) {
1283 const float r2 = point.X() * point.X() + point.Y() * point.Y();
1289 if (minR2 > MaxRadius * MaxRadius) {
1292 std::vector<bool> candidateChip(mITSChipCentres.size(),
false);
1293 bool anyChip =
false;
1294 const float chipCut2 = (mRoadITS + ChipHalfDiag) * (mRoadITS + ChipHalfDiag);
1295 for (
size_t chip = 0; chip < mITSChipCentres.size(); chip++) {
1298 closest(mITSChipCentres[chip].X(), mITSChipCentres[chip].Y(), dist2, zTraj);
1299 if (dist2 < chipCut2) {
1300 candidateChip[chip] =
true;
1307 const auto window = timeWindowMUS(cosmicTime);
1308 const float zTimeTol = 0.5f * (window.second - window.first) / mTPCTBinMUS * mCorrMap->getVDrift();
1310 const float zShift = legsSide * (cosmicTime.tb - cosm.
getTimeMUS().getTimeStamp() / mTPCTBinMUS) * mCorrMap->getVDrift();
1314 constexpr int NLayers = 7;
1315 constexpr int NLayersIB = 3;
1316 constexpr int MaxHitsIB = 5;
1322 Candidate
best[2][NLayers][MaxHitsIB];
1325 for (
const auto& rof :
data.getITSClustersROFRecords()) {
1326 const int rofBC = rof.getBCData().differenceInBC(mTFStart);
1327 const float rofMUS = rofBC * o2::constants::lhc::LHCBunchSpacingMUS;
1328 if (rofMUS + rofLengthMUS < window.first || rofMUS > window.second) {
1331 for (
int idx = rof.getFirstEntry();
idx < rof.getFirstEntry() + rof.getNEntries();
idx++) {
1333 if (!candidateChip[
c.getSensorID()] || matched.count(idx)) {
1342 const auto global = geom->getMatrixL2G(
c.getSensorID()) * local;
1345 closest(global.X(), global.Y(), dist2, zTraj);
1346 const float normZ = (global.Z() - zTraj - zShift) / (mRoadITS + zTimeTol);
1347 const float score = std::max(dist2 / (mRoadITS * mRoadITS), normZ * normZ);
1348 const int half = global.Y() < pcaY ? 0 : 1;
1349 const int layer = geom->getLayer(
c.getSensorID());
1350 if (layer < 0 || layer >= NLayers) {
1354 int slot = (
layer < NLayersIB ? MaxHitsIB : 1) - 1;
1355 if (!(score < candidates[slot].score)) {
1358 for (; slot > 0 && score < candidates[slot - 1].score; slot--) {
1359 candidates[slot] = candidates[slot - 1];
1361 candidates[slot] = {
idx, rofBC, score};
1367 if (candidate.index < 0) {
1370 const auto&
c =
clusters[candidate.index];
1371 auto& cl = out.emplace_back();
1372 cl.chipID =
c.getSensorID();
1373 cl.row =
c.getRow();
1374 cl.col =
c.getCol();
1375 cl.pattID =
c.getPatternID();
1376 cl.rofBC = candidate.rofBC;
1380 requests.push_back({icosm,
int(out.size()) - 1, candidate.index});
1387void CosmicsClusterCollectorSpec::fillITSPatterns(
const RecoContainer&
data, std::vector<ITSPattRequest>& requests, std::vector<o2::dataformats::TrackCosmicsExtended>& cosmics)
const
1391 if (!mNoDictWarned) {
1392 LOGP(warning,
"No ITS cluster dictionary: patterns of ITS clusters of cosmics are not stored");
1393 mNoDictWarned =
true;
1397 std::sort(requests.begin(), requests.end(), [](
const ITSPattRequest&
a,
const ITSPattRequest&
b) { return a.index < b.index; });
1399 auto pattIt =
data.getITSClustersPatterns().begin();
1401 for (
int k = 0; k < (
int)
clusters.size() &&
ir < requests.size(); k++) {
1402 const auto pattID =
clusters[k].getPatternID();
1406 const auto start = pattIt;
1408 for (;
ir < requests.size() && requests[
ir].
index == k;
ir++) {
1409 auto& cosm = cosmics[requests[
ir].cosmic];
1410 cosm.clITS[requests[
ir].cluster].pattEntry = cosm.itsPatterns.size();
1411 cosm.itsPatterns.insert(cosm.itsPatterns.end(),
start, pattIt);
1416void CosmicsClusterCollectorSpec::addTRD(
const RecoContainer&
data,
GTrackID gid, uint8_t leg, std::vector<o2::dataformats::CosmicTRDTracklet>& out, std::unordered_set<int>& matched)
const
1420 const auto trigs =
data.getTRDTriggerRecords();
1422 const int it = trk.getTrackletIndex(
layer);
1426 auto& tr = out.emplace_back();
1427 tr.word =
tracklets[it].getTrackletWord();
1432 auto trig = std::upper_bound(trigs.begin(), trigs.end(), it, [](
int v,
const o2::trd::TriggerRecord& t) { return v < t.getFirstTracklet(); });
1433 if (trig != trigs.begin()) {
1434 tr.trigBC = std::prev(trig)->getBCData().differenceInBC(mTFStart);
1439void CosmicsClusterCollectorSpec::flagDuplicates(std::vector<o2::dataformats::TrackCosmicsExtended>& cosmics)
const
1444 constexpr float MinSharedFraction = 0.3f;
1445 const size_t n = cosmics.size();
1449 std::vector<std::vector<uint64_t>>
keys(
n);
1450 std::vector<int> nAttached(
n, 0);
1451 for (
size_t ic = 0; ic <
n; ic++) {
1452 for (
const auto* legClusters : {&cosmics[ic].clTPCBottom, &cosmics[ic].clTPCTop}) {
1453 for (
const auto&
c : *legClusters) {
1454 keys[ic].push_back((uint64_t(
c.sector) << 56) | (uint64_t(
c.row) << 48) | (uint64_t(
c.cl.timeFlagsPacked) << 16) |
c.cl.padPacked);
1455 nAttached[ic] +=
c.isAttached();
1460 std::vector<int> order(
n);
1461 std::iota(order.begin(), order.end(), 0);
1462 std::stable_sort(order.begin(), order.end(), [&](
int a,
int b) {
1463 const bool timedA = cosmics[a].hasTOFTime();
1464 const bool timedB = cosmics[b].hasTOFTime();
1465 return timedA != timedB ? timedA : nAttached[a] > nAttached[b];
1467 std::vector<int> kept;
1468 for (
int ic : order) {
1469 for (
int ik : kept) {
1470 std::vector<uint64_t> shared;
1473 if (nMin > 0 && shared.size() >= MinSharedFraction * nMin) {
1474 cosmics[ic].duplicateOf = ik;
1478 if (cosmics[ic].duplicateOf < 0) {
1489 const bool absTimeKnown = cosm.
cosmic.
getTimeMUS().getTimeStampError() < mMaxAbsTimeErr;
1490 int nAttached[2] = {0, 0};
1491 int nRoad[2] = {0, 0};
1492 int side[2] = {-2, -2};
1493 std::vector<int> clLeg;
1494 std::vector<int> clFlags;
1495 std::vector<int> clSector;
1496 std::vector<int> clRow;
1497 std::vector<float> clPad;
1498 std::vector<float> clTime;
1499 std::vector<float> clQMax;
1500 std::vector<float> clQTot;
1501 std::vector<float> clX;
1502 std::vector<float> clY;
1503 std::vector<float> clZ;
1504 std::vector<float> clZCos;
1505 std::vector<float> clGx;
1506 std::vector<float> clGy;
1508 const std::vector<o2::dataformats::CosmicTPCCluster>* legClusters[2] = {&cosm.
clTPCBottom, &cosm.
clTPCTop};
1509 for (
int leg = 0; leg < 2; leg++) {
1510 if (legs[leg]->getNClusters() == 0) {
1513 side[leg] = tpcSide(*legs[leg]);
1514 for (
const auto&
c : *legClusters[leg]) {
1516 const float vertexTime =
c.isAbsTime() ? timeCosmic : legs[leg]->getTime0();
1520 mCorrMap->Transform(
c.sector,
c.row,
c.cl.getPad(),
c.cl.getTime(),
x,
y,
z, vertexTime);
1524 mCorrMap->Transform(
c.sector,
c.row,
c.cl.getPad(),
c.cl.getTime(), xCos, yCos, zCos, timeCosmic);
1526 const float sinAlpha = std::sin(
alpha);
1527 const float cosAlpha = std::cos(
alpha);
1528 clLeg.push_back(leg);
1529 clFlags.push_back(
c.flags);
1530 clSector.push_back(
c.sector);
1531 clRow.push_back(
c.row);
1532 clPad.push_back(
c.cl.getPad());
1533 clTime.push_back(
c.cl.getTime());
1534 clQMax.push_back(
c.cl.getQmax());
1535 clQTot.push_back(
c.cl.getQtot());
1539 clZCos.push_back(zCos);
1540 clGx.push_back(
x * cosAlpha -
y * sinAlpha);
1541 clGy.push_back(
x * sinAlpha +
y * cosAlpha);
1542 (
c.isAttached() ? nAttached : nRoad)[leg]++;
1545 std::vector<int> itsLeg;
1546 std::vector<int> itsFlags;
1547 std::vector<int> itsChip;
1548 std::vector<int> itsRow;
1549 std::vector<int> itsCol;
1550 std::vector<int> itsPattID;
1551 std::vector<int> itsHasPatt;
1552 std::vector<int> itsRofBC;
1553 std::vector<float> itsGx;
1554 std::vector<float> itsGy;
1555 std::vector<float> itsGz;
1556 std::vector<float> itsXLoc;
1557 std::vector<float> itsZLoc;
1558 for (
const auto&
c : cosm.clITS) {
1561 if (
c.pattEntry >= 0) {
1564 pattern.acquirePattern(pattIt);
1572 if (!mITSChipCentres.empty()) {
1575 itsLeg.push_back(
c.leg);
1576 itsFlags.push_back(
c.flags);
1577 itsChip.push_back(
c.chipID);
1578 itsRow.push_back(
c.row);
1579 itsCol.push_back(
c.col);
1580 itsPattID.push_back(
c.pattID);
1581 itsHasPatt.push_back(
c.pattEntry >= 0);
1582 itsRofBC.push_back(
c.rofBC);
1583 itsGx.push_back(global.X());
1584 itsGy.push_back(global.Y());
1585 itsGz.push_back(global.Z());
1586 itsXLoc.push_back(local.X());
1587 itsZLoc.push_back(local.Z());
1589 const auto& dbg = mDbgCosmics[icosm];
1591 (*mDebugOut) <<
"cosmics"
1592 <<
"tf=" << mDbgTF <<
"cosm=" << icosm <<
"t=" <<
time.getTimeStamp() <<
"tErr=" <<
time.getTimeStampError() <<
"absTime=" <<
int(absTimeKnown)
1594 <<
"tgl=" << cosm.
cosmic.getTgl() <<
"side0=" <<
side[0] <<
"side1=" <<
side[1] <<
"nAtt0=" << nAttached[0] <<
"nAtt1=" << nAttached[1]
1595 <<
"nRoad0=" << nRoad[0] <<
"nRoad1=" << nRoad[1] <<
"nITS=" <<
int(cosm.
clITS.size()) <<
"nTOF=" <<
int(cosm.
clTOF.size())
1598 <<
"clLeg=" << clLeg <<
"clFlags=" << clFlags <<
"clSector=" << clSector <<
"clRow=" << clRow <<
"clPad=" << clPad <<
"clTime=" << clTime
1599 <<
"clQMax=" << clQMax <<
"clQTot=" << clQTot <<
"clX=" << clX <<
"clY=" << clY <<
"clZ=" << clZ <<
"clZCos=" << clZCos <<
"clGx=" << clGx
1600 <<
"clGy=" << clGy <<
"roadLeg=" << dbg.roadLeg <<
"roadFrame=" << dbg.roadFrame <<
"roadSector=" << dbg.roadSector <<
"roadRow=" << dbg.roadRow
1601 <<
"roadX=" << dbg.roadX <<
"roadY=" << dbg.roadY <<
"roadZ=" << dbg.roadZ <<
"roadZCos=" << dbg.roadZCos <<
"roadGx=" << dbg.roadGx
1602 <<
"roadGy=" << dbg.roadGy <<
"roadSnp=" << dbg.roadSnp <<
"roadTgl=" << dbg.roadTgl <<
"itsLeg=" << itsLeg <<
"itsFlags=" << itsFlags
1603 <<
"itsChip=" << itsChip <<
"itsRow=" << itsRow <<
"itsCol=" << itsCol <<
"itsPattID=" << itsPattID <<
"itsHasPatt=" << itsHasPatt
1604 <<
"itsRofBC=" << itsRofBC <<
"itsGx=" << itsGx <<
"itsGy=" << itsGy <<
"itsGz=" << itsGz <<
"itsXLoc=" << itsXLoc <<
"itsZLoc=" << itsZLoc
1605 <<
"tofLeg=" << dbg.tofLeg <<
"tofChannel=" << dbg.tofChannel <<
"tofFlags=" << dbg.tofFlags <<
"tofTimeRaw=" << dbg.tofTimeRaw
1606 <<
"tofTime=" << dbg.tofTime <<
"tofTot=" << dbg.tofTot <<
"tofX=" << dbg.tofX <<
"tofY=" << dbg.tofY <<
"tofZ=" << dbg.tofZ <<
"tofGx=" << dbg.tofGx
1607 <<
"tofGy=" << dbg.tofGy <<
"trdLeg=" << dbg.trdLeg <<
"trdLayer=" << dbg.trdLayer <<
"trdX=" << dbg.trdX <<
"trdY=" << dbg.trdY <<
"trdZ=" << dbg.trdZ
1608 <<
"trdDy=" << dbg.trdDy <<
"trdDz=" << dbg.trdDz <<
"trdTrigMUS=" << dbg.trdTrigMUS <<
"\n";
1611void CosmicsClusterCollectorSpec::writeDebugTOF(
const o2::tof::Cluster&
c,
int icosm,
int leg, uint8_t
flags)
const
1615 const float sinAlpha = std::sin(
alpha);
1616 const float cosAlpha = std::cos(
alpha);
1617 auto& dbg = mDbgCosmics[icosm];
1618 dbg.tofLeg.push_back(leg);
1619 dbg.tofChannel.push_back(
c.getMainContributingChannel());
1620 dbg.tofFlags.push_back(
flags);
1621 dbg.tofTimeRaw.push_back(
c.getTimeRaw());
1622 dbg.tofTime.push_back(
c.getTime());
1623 dbg.tofTot.push_back(
c.getTot());
1624 dbg.tofX.push_back(
c.getX());
1625 dbg.tofY.push_back(
c.getY());
1626 dbg.tofZ.push_back(
c.getZ());
1627 dbg.tofGx.push_back(
c.getX() * cosAlpha -
c.getY() * sinAlpha);
1628 dbg.tofGy.push_back(
c.getX() * sinAlpha +
c.getY() * cosAlpha);
1645 LOGP(info,
"Cosmics cluster collector: {} cosmics, {} attached and {} road TPC clusters; Cpu: {:.3e} Real: {:.3e} s in {} slots",
1646 mNCosmics, mNClAttached, mNClCorridor, mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1);
1651 if (itsStag && roadDets[DetID::ITS]) {
1652 LOGP(warning,
"Staggered ITS clusters are not supported: ITS road of cosmics disabled");
1653 roadDets &=
~DetID::getMask(DetID::ITS);
1655 auto dataRequest = std::make_shared<DataRequest>();
1656 dataRequest->setITSPerLayer(itsStag);
1657 dataRequest->requestTracks(
src,
false);
1659 dataRequest->requestClusters(
src,
false);
1660 if (roadDets[DetID::ITS]) {
1661 dataRequest->requestITSClusters(
false);
1663 if (roadDets[DetID::TOF]) {
1664 dataRequest->requestTOFClusters(
false);
1666 if (roadDets[DetID::TRD]) {
1667 dataRequest->requestTRDTracklets(
false);
1669 dataRequest->requestCoscmicTracks(useMC);
1670 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(
false,
1674 roadDets[DetID::TOF],
1676 dataRequest->inputs,
1680 std::vector<OutputSpec> outputs;
1681 outputs.emplace_back(
"GLO",
"COSMFULL", 0, Lifetime::Timeframe);
1682 outputs.emplace_back(
"GLO",
"COSMFULLTF", 0, Lifetime::Timeframe);
1683 outputs.emplace_back(
"GLO",
"COSMFULLTFID", 0, Lifetime::Timeframe);
1686 "cosmics-cluster-collector",
1689 AlgorithmSpec{adaptFromTask<CosmicsClusterCollectorSpec>(dataRequest, ggRequest, useMC, roadDets)},
1691 {
"corridor-width", VariantType::Float, 1.f, {
"half-width of the road around each leg [cm]"}},
1692 {
"max-abs-time-err", VariantType::Float, 0.5f, {
"max. time error of a cosmic [mus] to search the other TPC side of its one-side legs"}},
1693 {
"max-cosmics-per-tf", VariantType::Int, 100, {
"write at most this many cosmics per TF (with their clusters), the others are dropped"}},
1694 {
"tof-road-width", VariantType::Float, 5.f, {
"half-width of the road at the TOF [cm]"}},
1695 {
"tof-flight-tolerance", VariantType::Float, 2.f, {
"max. deviation of the top/bottom TOF time difference from the muon's flight time [ns]"}},
1696 {
"tof-time-error", VariantType::Float, 0.1f, {
"error of a cosmic's TOF time for the TPC other-side corridor and the TRD / ITS roads [mus]"}},
1697 {
"trd-road-width", VariantType::Float, 5.f, {
"half-width of the road at the TRD [cm] (in z plus the pad length)"}},
1698 {
"its-road-width", VariantType::Float, 1.5f, {
"half-width of the road in the ITS [cm]"}},
1699 {
"debug-tree", VariantType::Bool,
false, {
"write cosmics_collector_debug.root with transformed clusters and road points (test runs)"}}}};
header::DataOrigin origin
Class of a TPC cluster in TPC-native coordinates (row, time)
General auxilliary methods.
Definition of the ITSMFT compact cluster.
Collects the raw clusters of matched cosmics (attached + road around the legs) for offline refits.
std::vector< std::string > keys
Helper for geometry and GRP related CCDB requests.
Definition of the GeometryTGeo class.
std::vector< o2::its::TrackITS > tracks
Header to collect LHC related constants.
Configurable params for cosmics matching.
Definition of the parameter class for the detector electronics.
Declarations of 2D primitives.
Definition of the SegmentationAlpide class.
Matched cosmic track with the raw clusters of its legs and of the road around them,...
Result of top-bottom cosmic tracks leg matching.
Definition of the ITS track.
Helper class to obtain TPC clusters / digits / labels from DPL.
void checkUpdates(o2::framework::ProcessingContext &pc)
static GRPGeomHelper & instance()
void setRequest(std::shared_ptr< GRPGeomRequest > req)
GPUd() value_type estimateLTFast(o2 static GPUd() float estimateLTIncrement(const o2 PropagatorImpl * Instance(bool uninitialized=false)
static const ParameterElectronics & Instance()
Static class with identifiers, bitmasks and names for ALICE detectors.
const Mat3D & getMatrixL2G(int sensID) const
T get(const char *key) const
void snapshot(const Output &spec, T const &object)
ServiceRegistryRef services()
ConfigParamRegistry const & options()
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
void finaliseCCDB(ConcreteDataMatcher &matcher, void *obj) final
void endOfStream(EndOfStreamContext &ec) final
This is invoked whenever we have an EndOfStream event.
~CosmicsClusterCollectorSpec() override=default
void run(ProcessingContext &pc) final
CosmicsClusterCollectorSpec(std::shared_ptr< DataRequest > dr, std::shared_ptr< o2::base::GRPGeomRequest > gr, bool useMC, DetID::mask_t roadDets)
void init(InitContext &ic) final
int32_t RefitTrackAsTrackParCov(o2::tpc::TrackTPC &trk, bool outward=false, bool resetCov=false)
static GeometryTGeo * Instance()
static void skipPattern(iterator &pattIt)
static constexpr unsigned short InvalidPatternID
static void detectorToLocalUnchecked(L row, L col, T &xRow, T &zCol)
math_utils::Point3D< T > getClusterCoordinates(const CompCluster &cl) const
bool isGroup(int n) const
Returns true if the element corresponds to a group of rare topologies.
Header for data corresponding to the same hardware trigger adapted from DataFormatsITSMFT/ROFRecord.
GLfloat GLfloat GLfloat alpha
GLdouble GLdouble GLdouble GLdouble top
GLuint const GLchar * name
GLboolean GLboolean GLboolean b
GLuint GLsizei GLsizei * length
GLsizei const GLchar *const * path
GLenum GLuint GLint GLint layer
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
GLboolean GLboolean GLboolean GLboolean a
GLubyte GLubyte GLubyte GLubyte w
GLdouble GLdouble GLdouble z
constexpr o2::header::DataOrigin gDataOriginTPC
uint8_t int statusCode int
uint8_t itsSharedClusterMap uint8_t
double norm(const Vec3 &vector)
Defining ITS Vertex explicitly as messageable.
o2::dataformats::GlobalTrackID::mask_t getLegITSSources(o2::dataformats::GlobalTrackID::mask_t src)
framework::DataProcessorSpec getCosmicsClusterCollectorSpec(o2::dataformats::GlobalTrackID::mask_t src, bool useMC, bool itsStag, o2::detectors::DetID::mask_t roadDets)
return *o2::gpu::CAMath::Sqrt(xX0) *(1.f+0.038f *o2 const float const float const float const float rOut
return *o2::gpu::CAMath::Sqrt(xX0) *(1.f+0.038f *o2 const float const float rIn
return *o2::gpu::CAMath::Sqrt(xX0) *(1.f+0.038f *o2 const float const float const float rMid
const bool const bool const int FollowDirection BestTrial TrackITSInternal< NLayers > & best
o2::track::TrackParametrization< float > par
const float const float const float const float std::array< float, 3 > std::array< float, 3 > & direction
int angle2Sector(float phi)
float sector2Angle(int sect)
float dSector(float phi, int nSectors=18, float sectorPhaseRad=0.f)
Fractional azimuthal position inside a periodic sector pattern.
Enum< T >::Iterator begin(Enum< T >)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
static void fillTFIDInfo(o2::framework::ProcessingContext &pc, o2::dataformats::TFIDInfo &ti)
GlobalIDSet getSingleDetectorRefs(GTrackID gidx) const
const o2::tpc::TrackTPC & getTPCTrack(GTrackID id) const
auto getTPCTracksClusterRefs() const
auto getTOFClusters() const
gsl::span< const unsigned char > clusterShMapTPC
externally set TPC clusters sharing map
void collectData(o2::framework::ProcessingContext &pc, const DataRequest &request)
std::unique_ptr< o2::tpc::internal::getWorkflowTPCInput_ret > inputsTPCclusters
gsl::span< const unsigned int > occupancyMapTPC
externally set TPC clusters occupancy map
auto getCosmicTracks() const
auto getCosmicTrackMCLabel(int i) const
o2::InteractionRecord ir(0, 0)
std::vector< Cluster > clusters
std::array< uint16_t, 5 > pattern
std::vector< Tracklet64 > tracklets