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 buildUsedMap(
const RecoContainer&
data, std::vector<std::pair<float, float>>& time0Windows);
170 void addTPCAttached(
const RecoContainer&
data,
const o2::tpc::TrackTPC& trk, std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const;
180 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;
182 std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const;
183 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,
184 float dxRow, std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const;
185 void addDebugRoadPoint(
int sector,
float x,
float y,
float z,
float snp,
float tgl,
int row,
float vertexTime,
int frameCode)
const;
186 struct ITSPattRequest {
191 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;
192 void fillITSPatterns(
const RecoContainer&
data, std::vector<ITSPattRequest>& requests, std::vector<o2::dataformats::TrackCosmicsExtended>& cosmics)
const;
193 void addTOF(
const RecoContainer&
data,
GTrackID gid, uint8_t leg, std::vector<o2::dataformats::CosmicTOFCluster>& out, std::unordered_set<int>& matched)
const;
194 void addTRD(
const RecoContainer&
data,
GTrackID gid, uint8_t leg, std::vector<o2::dataformats::CosmicTRDTracklet>& out, std::unordered_set<int>& matched)
const;
195 std::pair<float, float> timeWindowMUS(
const CosmicTime& cosmicTime)
const;
196 bool predictOutward(
const o2::tpc::TrackTPC& leg,
const CosmicTime& cosmicTime,
int sector,
float x,
float&
y,
float&
z)
const;
197 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;
199 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;
200 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,
201 const std::unordered_set<int>& matched)
const;
202 void cacheITSChipCentres();
204 void flagDuplicates(std::vector<o2::dataformats::TrackCosmicsExtended>& cosmics)
const;
207 std::shared_ptr<DataRequest> mDataRequest;
208 std::shared_ptr<o2::base::GRPGeomRequest> mGGCCDBRequest;
211 std::vector<bool> mUsed;
213 float mCorridor = 1.f;
214 float mMaxAbsTimeErr = 0.5f;
215 size_t mMaxCosmicsPerTF = 100;
217 float mRoadTOF = 5.f;
218 float mTOFFlightTol = 2.f;
219 float mTOFTimeErr = 0.1f;
220 float mRoadTRD = 5.f;
221 float mRoadITS = 1.5f;
222 std::vector<o2::math_utils::Point3D<float>> mITSChipCentres;
223 float mTPCTBinMUS = 0.2f;
226 mutable bool mStaggeredWarned =
false;
227 mutable bool mNoDictWarned =
false;
228 mutable bool mTRDMismatchWarned =
false;
229 std::unique_ptr<o2::utils::TreeStreamRedirector> mDebugOut;
233 float mDbgTauC = 0.f;
236 std::vector<int> roadLeg;
237 std::vector<int> roadFrame;
238 std::vector<int> roadSector;
239 std::vector<int> roadRow;
240 std::vector<float> roadX;
241 std::vector<float> roadY;
242 std::vector<float> roadZ;
243 std::vector<float> roadZCos;
244 std::vector<float> roadGx;
245 std::vector<float> roadGy;
246 std::vector<float> roadSnp;
247 std::vector<float> roadTgl;
248 std::vector<int> tofLeg;
249 std::vector<int> tofChannel;
250 std::vector<int> tofFlags;
251 std::vector<double> tofTimeRaw;
252 std::vector<double> tofTime;
253 std::vector<float> tofTot;
254 std::vector<float> tofX;
255 std::vector<float> tofY;
256 std::vector<float> tofZ;
257 std::vector<float> tofGx;
258 std::vector<float> tofGy;
259 std::vector<int> trdLeg;
260 std::vector<int> trdLayer;
261 std::vector<float> trdX;
262 std::vector<float> trdY;
263 std::vector<float> trdZ;
264 std::vector<float> trdDy;
265 std::vector<float> trdDz;
266 std::vector<float> trdTrigMUS;
268 mutable std::vector<DebugCosmic> mDbgCosmics;
269 size_t mNCosmics = 0;
270 size_t mNClAttached = 0;
271 size_t mNClCorridor = 0;
280 mCorridor = ic.
options().
get<
float>(
"corridor-width");
281 mMaxAbsTimeErr = ic.
options().
get<
float>(
"max-abs-time-err");
282 mMaxCosmicsPerTF = std::max(0, ic.
options().
get<
int>(
"max-cosmics-per-tf"));
283 mRoadTOF = ic.
options().
get<
float>(
"tof-road-width");
284 mTOFFlightTol = ic.
options().
get<
float>(
"tof-flight-tolerance");
285 mTOFTimeErr = ic.
options().
get<
float>(
"tof-time-error");
286 mRoadTRD = ic.
options().
get<
float>(
"trd-road-width");
287 mRoadITS = ic.
options().
get<
float>(
"its-road-width");
290 const std::string
name = timesliceId == 0 ?
"cosmics_collector_debug.root" : fmt::format(
"cosmics_collector_debug_{}.root", timesliceId);
291 mDebugOut = std::make_unique<o2::utils::TreeStreamRedirector>(
name.c_str(),
"recreate");
300 updateTimeDependentParams(pc);
306 tfInfo.
vDrift = mCorrMap->getVDrift();
307 tfInfo.
t0 = mCorrMap->getT0();
309 std::vector<o2::dataformats::TrackCosmicsExtended> cosmicsOut;
311 const size_t nCosmics = std::min(cosmics.size(), mMaxCosmicsPerTF);
312 if (nCosmics < cosmics.size()) {
313 LOGP(warning,
"{} cosmics in TF {}, only the first {} are written (max-cosmics-per-tf)", cosmics.size(), tfID.
tfCounter, nCosmics);
318 std::vector<std::pair<float, float>> time0Windows;
319 for (
size_t ic = 0; ic < nCosmics; ic++) {
320 for (
const auto leg : {cosmics[ic].getRefBottom(), cosmics[ic].getRefTop()}) {
324 time0Windows.emplace_back(time0 - maxDistTB, time0 + maxDistTB);
328 buildUsedMap(recoData, time0Windows);
330 std::vector<ITSPattRequest> pattRequests;
331 std::unique_ptr<o2::gpu::GPUO2InterfaceRefit> tpcRefitter;
340 mDbgCosmics.assign(nCosmics, DebugCosmic{});
342 for (
size_t ic = 0; ic < nCosmics; ic++) {
343 const auto& cosm = cosmics[ic];
344 auto& out = cosmicsOut.emplace_back();
349 const GTrackID legs[2] = {cosm.getRefBottom(), cosm.getRefTop()};
351 std::vector<o2::dataformats::CosmicTPCCluster>* tpcCl[2] = {&out.clTPCBottom, &out.clTPCTop};
352 std::unordered_set<int> matchedITS;
353 std::unordered_set<int> matchedTOF;
354 std::unordered_set<int> matchedTRD;
355 for (uint8_t leg = 0; leg < 2; leg++) {
359 (leg == 0 ? out.tpcBottom : out.tpcTop) = *tpcLegs[leg];
362 addITS(recoData, refs[
GTrackID::ITS], leg, out.clITS, ic, pattRequests, matchedITS);
365 addTOF(recoData, refs[
GTrackID::TOF], leg, out.clTOF, matchedTOF);
371 addTRD(recoData, refs[
GTrackID::TRD], leg, out.trdTracklets, matchedTRD);
374 CosmicTime cosmicTime;
375 cosmicTime.tb = cosm.getTimeMUS().getTimeStamp() / mTPCTBinMUS;
376 cosmicTime.errTB = cosm.getTimeMUS().getTimeStampError() / mTPCTBinMUS;
377 cosmicTime.known = cosm.getTimeMUS().getTimeStampError() < mMaxAbsTimeErr;
381 if (mRoadDets[DetID::TOF]) {
382 roadTOF(recoData, tpcLegs, cosmicTime, ic, out.clTOF, matchedTOF, out.timeTOFMUS, out.scoreTOFPair, out.scoreTOFReversed);
385 polish(tpcLegs, out.timeTOFMUS, *tpcRefitter, out);
387 CosmicTime roadTime = cosmicTime;
388 if (out.hasTOFTime()) {
389 roadTime.tb = out.timeTOFMUS / mTPCTBinMUS;
390 roadTime.errTB = mTOFTimeErr / mTPCTBinMUS;
391 roadTime.known =
true;
393 mDbgTauC = roadTime.tb;
394 std::unordered_set<uint32_t> taken;
395 for (
int leg = 0; leg < 2; leg++) {
397 addTPCAttached(recoData, *tpcLegs[leg], *tpcCl[leg], taken);
398 mNClAttached += tpcCl[leg]->size();
401 for (
int leg = 0; leg < 2; leg++) {
403 const size_t nAttached = tpcCl[leg]->size();
405 addTPCCorridor(recoData, *tpcLegs[leg], roadTime, *tpcCl[leg], taken);
406 mNClCorridor += tpcCl[leg]->size() - nAttached;
409 if (mRoadDets[DetID::TRD]) {
410 roadTRD(recoData, tpcLegs, roadTime, ic, out.trdTracklets, matchedTRD);
412 if (mRoadDets[DetID::ITS]) {
415 if (tpcLegs[0] && tpcLegs[1] && legs[0].getSource() ==
GTrackID::TPC && legs[1].getSource() ==
GTrackID::TPC && tpcSide(*tpcLegs[0]) == tpcSide(*tpcLegs[1])) {
416 legsSide = tpcSide(*tpcLegs[0]);
418 roadITS(recoData, cosm, roadTime, legsSide, ic, out.clITS, pattRequests, matchedITS);
421 if (!pattRequests.empty()) {
422 fillITSPatterns(recoData, pattRequests, cosmicsOut);
424 flagDuplicates(cosmicsOut);
426 for (
size_t ic = 0; ic < cosmicsOut.size(); ic++) {
427 writeDebug(cosmicsOut[ic], ic);
430 mNCosmics += cosmicsOut.size();
431 LOGP(info,
"Collected clusters for {} cosmics in TF {}", cosmicsOut.size(), tfID.
tfCounter);
438void CosmicsClusterCollectorSpec::updateTimeDependentParams(
ProcessingContext& pc)
441 mCorrMap = &o2::gpu::TPCFastTransformPOD::get(pc.
inputs().
get<
const char*>(
"corrMap"));
444 if (mRoadDets[DetID::ITS] && mITSChipCentres.empty()) {
445 cacheITSChipCentres();
449void CosmicsClusterCollectorSpec::cacheITSChipCentres()
452 geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G));
453 mITSChipCentres.resize(geom->getNumberOfChips());
454 for (
int chip = 0; chip < geom->getNumberOfChips(); chip++) {
459void CosmicsClusterCollectorSpec::buildUsedMap(
const RecoContainer&
data, std::vector<std::pair<float, float>>& time0Windows)
462 std::sort(time0Windows.begin(), time0Windows.end());
463 std::vector<std::pair<float, float>> merged;
464 for (
const auto& window : time0Windows) {
465 if (!merged.empty() && window.first <= merged.back().second) {
466 merged.back().second = std::max(merged.back().second, window.second);
468 merged.push_back(window);
473 const auto refs =
data.getTPCTracksClusterRefs();
474 mUsed.assign(
clusters.nClustersTotal,
false);
475 for (
const auto& trk :
tracks) {
476 const float time0 = trk.getTime0();
477 const auto window = std::upper_bound(merged.begin(), merged.end(), time0, [](
float t,
const std::pair<float, float>&
w) { return t < w.first; });
478 if (window == merged.begin() || time0 > std::prev(window)->second) {
481 for (
int j = 0;
j < trk.getNClusterReferences();
j++) {
485 trk.getClusterReference(refs,
j, sector,
row, clIdx);
486 mUsed[
clusters.clusterOffset[sector][
row] + clIdx] =
true;
491void CosmicsClusterCollectorSpec::addTPCAttached(
const RecoContainer&
data,
const o2::tpc::TrackTPC& trk, std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const
494 const auto refs =
data.getTPCTracksClusterRefs();
495 for (
int j = 0;
j < trk.getNClusterReferences();
j++) {
499 trk.getClusterReference(refs,
j, sector,
row, clIdx);
500 if (!taken.insert(
clusters.clusterOffset[sector][
row] + clIdx).second) {
503 auto& cl = out.emplace_back();
513 if (std::abs(inner.getCurvature(bz)) < 1e-5f) {
515 const auto point = inner.getXYZGlo();
516 const float phi = inner.getPhi();
517 dirX = std::cos(phi);
518 dirY = std::sin(phi);
519 const float proj = point.X() * dirX + point.Y() * dirY;
520 pcaX = point.X() - proj * dirX;
521 pcaY = point.Y() - proj * dirY;
524 float sinAlpha = 0.f;
525 float cosAlpha = 0.f;
526 inner.getCircleParams(bz, circle, sinAlpha, cosAlpha);
529 const float centerDist = std::sqrt(centerX * centerX + centerY * centerY);
530 if (centerDist < 1e-3f) {
534 pcaX = centerX * (1.f - circle.
rC / centerDist);
535 pcaY = centerY * (1.f - circle.
rC / centerDist);
539 const auto pointIn = inner.getXYZGlo();
540 const auto pointOut = outer.getXYZGlo();
541 const float distIn2 = (pointIn.X() - pcaX) * (pointIn.X() - pcaX) + (pointIn.Y() - pcaY) * (pointIn.Y() - pcaY);
542 const float distOut2 = (pointOut.X() - pcaX) * (pointOut.X() - pcaX) + (pointOut.Y() - pcaY) * (pointOut.Y() - pcaY);
543 const int sideIn =
side(pointIn.X(), pointIn.Y());
544 const int sideOut =
side(pointOut.X(), pointOut.Y());
545 constexpr float MinDist2 = 10.f * 10.f;
546 if (sideIn == sideOut) {
548 }
else if (std::min(distIn2, distOut2) < MinDist2) {
549 sign = distIn2 > distOut2 ? sideIn : sideOut;
555void 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
559 const float vDrift = mCorrMap->getVDrift();
561 const float time0Leg = trk.getTime0();
562 const int legSide = tpcSide(trk);
567 frames[nFrames++] = {time0Leg, 0.f, 0.f, 0, 2 * NSectorsA, 0};
569 frames[nFrames++] = {time0Leg, 0.f, 0.f, legSide > 0 ? 0 : NSectorsA, legSide > 0 ? NSectorsA : 2 * NSectorsA, 0};
570 if (cosmicTime.known) {
571 frames[nFrames++] = {cosmicTime.tb, legSide * (cosmicTime.tb - time0Leg) * vDrift, cosmicTime.errTB * vDrift,
572 legSide > 0 ? NSectorsA : 0, legSide > 0 ? 2 * NSectorsA : NSectorsA,
o2::dataformats::CosmicTPCCluster::AbsTime};
578 branch.init(refPar[0], refPar[1], mBz);
579 const auto pointIn = refPar[0].getXYZGlo();
580 const auto pointOut = refPar[1].getXYZGlo();
581 const float rIn = std::hypot(pointIn.X(), pointIn.Y());
582 const float rOut = std::hypot(pointOut.X(), pointOut.Y());
585 for (
int iFrame = 0; iFrame < nFrames; iFrame++) {
586 const auto& frame = frames[iFrame];
587 for (
int sector = frame.sectorMin; sector < frame.sectorMax; sector++) {
589 const float sinAlpha = std::sin(
alpha);
590 const float cosAlpha = std::cos(
alpha);
591 const bool sideA = sector < NSectorsA;
592 for (
int iPar = 0; iPar < 2; iPar++) {
593 auto par = refPar[iPar];
594 par.setZ(
par.getZ() + frame.dz);
601 for (
int row = 0;
row < o2::tpc::constants::MAXGLOBALPADROW;
row++) {
603 if ((xRow < rMid) != (iPar == 0)) {
607 if (!parRow.propagateParamTo(xRow, mBz)) {
611 constexpr float CoarseMargin = 10.f;
612 if (std::abs(parRow.getY()) > xRow * TanSector + mCorridor + CoarseMargin || outsideDriftVolume(sideA, parRow.getZ(), mCorridor + frame.zTolerance + CoarseMargin)) {
617 const float zInside = sideA ? std::clamp(parRow.getZ(), 0.f, zLength) :
std::
clamp(parRow.getZ(), -zLength, 0.f);
618 mCorrMap->InverseTransformYZtoX(sector,
row, parRow.getY(), zInside, xReal);
619 if (!parRow.propagateParamTo(xReal, mBz)) {
622 const float y = parRow.getY();
623 const float z = parRow.getZ();
624 if (std::abs(
y) > xRow * TanSector + mCorridor) {
627 if (outsideDriftVolume(sideA,
z, mCorridor + frame.zTolerance)) {
630 if (!branch.accept(xRow * cosAlpha -
y * sinAlpha, xRow * sinAlpha +
y * cosAlpha)) {
634 addDebugRoadPoint(sector, xReal,
y,
z, parRow.getSnp(), parRow.getTgl(),
row, frame.vertexTime, frame.flag != 0);
636 searchRow(
clusters, sector,
row,
y,
z, parRow.getSnp(), parRow.getTgl(), frame.vertexTime, frame.zTolerance, frame.flag, 0.f, out, taken);
643 const bool splitAtRMid =
rOut >
rIn;
644 for (
int iPar = 0; iPar < (splitAtRMid ? 2 : 1); iPar++) {
645 auto par = refPar[iPar];
646 par.setZ(
par.getZ() + frame.dz);
647 walkLowAngleRoad(
clusters, par, iPar == 0, splitAtRMid ? rMid :
std::numeric_limits<float>::
max(), branch, frame, out, taken);
653 const RoadFrame& frame, std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const
656 constexpr float CosSector = 0.98480775f;
657 constexpr float Step = 0.5f;
658 constexpr float MaxPath = 600.f;
659 constexpr float MaxEntryPath = 20.f;
660 constexpr float MinSnp = 0.8f;
661 constexpr float XMargin = 10.f;
662 constexpr int NRows = o2::tpc::constants::MAXGLOBALPADROW;
666 std::array<float, NSectorsA> sinSector{};
667 std::array<float, NSectorsA> cosSector{};
668 for (
int sector = 0; sector < NSectorsA; sector++) {
670 sinSector[sector] = std::sin(
alpha);
671 cosSector[sector] = std::cos(
alpha);
674 bool startInside =
false;
677 if (direction == 1) {
680 bool entered =
direction == 1 && startInside;
682 for (
float path = direction == 0 ? 0.f : Step;
path < MaxPath;
path += Step) {
684 if (
path > 0.f && (!
par.rotateParam(
par.getPhi()) || !
par.propagateParamTo(
par.getX() + Step, mBz))) {
687 const auto pos =
par.getXYZGlo();
688 const float r = std::hypot(
pos.X(),
pos.Y());
689 if (
r > rHigh || std::abs(
pos.Z()) > zLength + mCorridor + frame.zTolerance) {
694 if (
r < rLow || (
r < rMid) != innerPart || !branch.accept(
pos.X(),
pos.Y())) {
695 if (entered ||
path > MaxEntryPath) {
701 startInside = startInside ||
path == 0.f;
702 const float phiDir =
par.getPhi();
704 for (
int dSector = -1; dSector <= 1; dSector++) {
705 const int sectorInSide = (sectorPos + dSector + NSectorsA) % NSectorsA;
706 for (
int sector = sectorInSide; sector < 2 * NSectorsA; sector += NSectorsA) {
707 if (sector < frame.sectorMin || sector >= frame.sectorMax) {
710 const bool sideA = sector < NSectorsA;
711 if (outsideDriftVolume(sideA,
pos.Z(), mCorridor + frame.zTolerance)) {
715 const float sinAlpha = sinSector[sectorInSide];
716 const float cosAlpha = cosSector[sectorInSide];
717 const float x =
pos.X() * cosAlpha +
pos.Y() * sinAlpha;
718 const float y = -
pos.X() * sinAlpha +
pos.Y() * cosAlpha;
719 float snp = std::sin(phiDir -
alpha);
720 float tgl =
par.getTgl();
721 if (std::cos(phiDir -
alpha) < 0.f) {
725 if (std::abs(snp) < MinSnp || std::abs(
y) >
x * TanSector + mCorridor) {
728 const float zInside = sideA ? std::clamp(
pos.Z(), 0.f, zLength) :
std::
clamp(
pos.Z(), -zLength, 0.f);
732 while (rowFirst < rowEnd) {
733 const int rowMid = (rowFirst + rowEnd) / 2;
735 rowFirst = rowMid + 1;
742 mCorrMap->InverseTransformYZtoX(sector,
row,
y, zInside, xReal);
743 const float dxRow = xReal -
x;
744 if (std::abs(dxRow) > mCorridor) {
748 addDebugRoadPoint(sector,
x,
y,
pos.Z(), snp, tgl,
row, frame.vertexTime, 2 + (frame.flag != 0));
750 searchRow(
clusters, sector,
row,
y,
pos.Z(), snp, tgl, frame.vertexTime, frame.zTolerance, frame.flag, dxRow, out, taken);
758void 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,
759 float dxRow, std::vector<o2::dataformats::CosmicTPCCluster>& out, std::unordered_set<uint32_t>& taken)
const
763 const float vDrift = mCorrMap->getVDrift();
764 const float t0 = mCorrMap->getT0();
767 float yNominal = 0.f;
768 float zNominal = 0.f;
769 mCorrMap->InverseTransformYZtoNominalYZ(sector,
row,
y, zInside, yNominal, zNominal);
770 zNominal +=
z - zInside;
772 float driftLengthPred = 0.f;
774 const float timePred = driftLengthPred / vDrift +
t0 + vertexTime;
777 const float cosPhi = std::sqrt((1.f - snp) * (1.f + snp));
778 const float cosPhiWindow = std::max(cosPhi, 0.1f);
779 const float norm = 1.f / std::sqrt(1.f + tgl * tgl);
780 const float dirX = cosPhi *
norm;
781 const float dirY = snp *
norm;
782 const float dirZ = tgl *
norm;
783 const float corridor2 = mCorridor * mCorridor;
785 const float windowTime = (mCorridor * std::sqrt(cosPhiWindow * cosPhiWindow + tgl * tgl) / cosPhiWindow + zTolerance) / vDrift;
786 const auto* rowClusters =
clusters.clusters[sector][
row];
787 const uint32_t rowOffset =
clusters.clusterOffset[sector][
row];
788 for (uint32_t k = 0; k <
clusters.nClusters[sector][
row]; k++) {
789 const auto&
c = rowClusters[k];
790 const float time =
c.getTime();
791 const float pad =
c.getPad();
792 if (std::abs(
time - timePred) > windowTime || std::abs(pad - padPred) > windowPad) {
795 float yCluster = 0.f;
796 float zCluster = 0.f;
798 const float dy = yCluster - yNominal;
799 float dz = zCluster - zNominal;
800 if (zTolerance > 0.f) {
801 dz = std::abs(dz) > zTolerance ? dz - std::copysign(zTolerance, dz) : 0.f;
803 const float proj = dxRow * dirX + dy * dirY + dz * dirZ;
804 if (dxRow * dxRow + dy * dy + dz * dz - proj * proj > corridor2) {
807 if (!taken.insert(rowOffset + k).second) {
810 auto& cl = out.emplace_back();
818void CosmicsClusterCollectorSpec::addDebugRoadPoint(
int sector,
float x,
float y,
float z,
float snp,
float tgl,
int row,
float vertexTime,
int frameCode)
const
822 const float sinAlpha = std::sin(
alpha);
823 const float cosAlpha = std::cos(
alpha);
825 auto& dbg = mDbgCosmics[mDbgCosmic];
826 dbg.roadLeg.push_back(mDbgLeg);
827 dbg.roadFrame.push_back(frameCode);
828 dbg.roadSector.push_back(sector);
829 dbg.roadRow.push_back(
row);
830 dbg.roadX.push_back(
x);
831 dbg.roadY.push_back(
y);
832 dbg.roadZ.push_back(
z);
833 dbg.roadZCos.push_back(
z + (sideA ? 1.f : -1.f) * (mDbgTauC - vertexTime) * mCorrMap->getVDrift());
834 dbg.roadGx.push_back(
x * cosAlpha -
y * sinAlpha);
835 dbg.roadGy.push_back(
x * sinAlpha +
y * cosAlpha);
836 dbg.roadSnp.push_back(snp);
837 dbg.roadTgl.push_back(tgl);
840void 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
845 if (
data.getITSPerLayer()) {
846 if (!mStaggeredWarned) {
847 LOGP(warning,
"Staggered ITS clusters are not supported, ITS clusters of cosmics are not stored");
848 mStaggeredWarned =
true;
852 const auto& trk =
data.getITSTrack(gid);
853 const auto refs =
data.getITSTracksClusterRefs();
855 const auto rofs =
data.getITSClustersROFRecords();
856 for (
int i = 0;
i < trk.getNumberOfClusters();
i++) {
857 const int idx = refs[trk.getFirstClusterEntry() +
i];
859 auto& cl = out.emplace_back();
860 cl.chipID =
c.getSensorID();
863 cl.pattID =
c.getPatternID();
868 requests.push_back({icosm,
int(out.size()) - 1,
idx});
870 auto rof = std::upper_bound(rofs.begin(), rofs.end(), idx, [](
int v,
const o2::itsmft::ROFRecord&
r) { return v < r.getFirstEntry(); });
871 if (rof != rofs.begin()) {
872 cl.rofBC = std::prev(rof)->getBCData().differenceInBC(mTFStart);
877void CosmicsClusterCollectorSpec::addTOF(
const RecoContainer&
data,
GTrackID gid, uint8_t leg, std::vector<o2::dataformats::CosmicTOFCluster>& out, std::unordered_set<int>& matched)
const
879 const auto&
c =
data.getTOFClusters()[gid.getIndex()];
880 auto& cl = out.emplace_back();
881 cl.timeRaw =
c.getTimeRaw();
883 cl.channel =
c.getMainContributingChannel();
886 matched.insert(gid.getIndex());
889std::pair<float, float> CosmicsClusterCollectorSpec::timeWindowMUS(
const CosmicTime& cosmicTime)
const
892 const float timeMUS = cosmicTime.tb * mTPCTBinMUS;
893 const float errMUS = cosmicTime.errTB * mTPCTBinMUS;
894 const float halfWidth = cosmicTime.known ? 5.f * errMUS + 0.2f : errMUS;
895 return {timeMUS - halfWidth, timeMUS + halfWidth};
898bool CosmicsClusterCollectorSpec::predictOutward(
const o2::tpc::TrackTPC& leg,
const CosmicTime& cosmicTime,
int sector,
float x,
float&
y,
float&
z)
const
907 z =
par.getZ() + tpcSide(leg) * (cosmicTime.tb - leg.getTime0()) * mCorrMap->getVDrift();
911void 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
918 constexpr float MaxFlightMUS = 0.1f;
919 constexpr float CmPerNS = 29.9792458f;
920 const auto window = timeWindowMUS(cosmicTime);
921 const float zTimeTol = 0.5f * (window.second - window.first) / mTPCTBinMUS * mCorrMap->getVDrift();
922 const float vDriftPerMUS = mCorrMap->getVDrift() / mTPCTBinMUS;
923 const float cosmicTimeMUS = cosmicTime.tb * mTPCTBinMUS;
924 int legSide[2] = {0, 0};
925 float curvature = 0.f;
927 for (
int leg = 0; leg < 2; leg++) {
929 legSide[leg] = tpcSide(*legs[leg]);
930 curvature += std::abs(legs[leg]->getCurvature(mBz));
934 curvature = nLegs ? curvature / nLegs : 0.f;
940 float dzAtCosmicTime;
945 std::vector<Candidate> candidates[2];
947 int best[2] = {-1, -1};
948 float bestScore[2] = {1.f, 1.f};
951 const float timeMUS =
c.getTime() * 1e-6f;
952 if (timeMUS < window.first - MaxFlightMUS || timeMUS > window.second + MaxFlightMUS) {
955 const bool isMatched = matched.count(
i) > 0;
957 const float sinAlpha = std::sin(
alpha);
958 const float cosAlpha = std::cos(
alpha);
959 for (
int leg = 0; leg < 2; leg++) {
962 if (!legs[leg] || !predictOutward(*legs[leg], cosmicTime,
c.getSector(),
c.getX(),
y,
z)) {
965 const float normY = (
c.getY() -
y) / mRoadTOF;
966 const float normZ = (
c.getZ() -
z) / (mRoadTOF + zTimeTol);
967 const float score = std::max(normY * normY, normZ * normZ);
971 if (!isMatched && score < bestScore[leg]) {
972 bestScore[leg] = score;
975 candidates[leg].push_back(Candidate{
i, isMatched,
c.getTime() * 1e-3,
c.getY() -
y,
c.getZ() -
z,
c.getX() * cosAlpha -
c.getY() * sinAlpha,
976 c.getX() * sinAlpha +
c.getY() * cosAlpha,
c.getZ()});
979 float bestPairScore = -1.f;
980 float bestReversedScore = -1.f;
981 int bestPair[2] = {-1, -1};
982 for (
const auto& c0 : candidates[0]) {
983 for (
const auto& c1 : candidates[1]) {
984 if (c0.index == c1.index) {
988 const auto&
top = c0.gy > c1.gy ? c0 : c1;
989 const auto&
bottom = c0.gy > c1.gy ? c1 : c0;
992 const float halfAngleSin = 0.5f * curvature * chordXY;
993 const float arcXY = halfAngleSin > 1e-4f && halfAngleSin < 1.f ? 2.f * std::asin(halfAngleSin) / curvature : chordXY;
995 const float timeDiff = float(
top.timeNS -
bottom.timeNS);
996 const float flightDev = timeDiff +
length / CmPerNS;
997 const float reversedDev = timeDiff -
length / CmPerNS;
998 const bool reversed = std::abs(flightDev) > mTOFFlightTol;
999 if (reversed && std::abs(reversedDev) > mTOFFlightTol) {
1002 const double pairTimeNS = 0.5 * (c0.timeNS + c1.timeNS);
1003 const float shiftMUS = float(pairTimeNS * 1e-3) - cosmicTimeMUS;
1004 const float dz0 = c0.dzAtCosmicTime - legSide[0] * shiftMUS * vDriftPerMUS;
1005 const float dz1 = c1.dzAtCosmicTime - legSide[1] * shiftMUS * vDriftPerMUS;
1006 if (std::abs(dz0) > mRoadTOF || std::abs(dz1) > mRoadTOF) {
1009 const float timeDev = reversed ? reversedDev : flightDev;
1010 const float score = (c0.dy * c0.dy + c1.dy * c1.dy + dz0 * dz0 + dz1 * dz1) / (mRoadTOF * mRoadTOF) + timeDev * timeDev / (mTOFFlightTol * mTOFFlightTol);
1012 if (bestReversedScore < 0.f || score < bestReversedScore) {
1013 bestReversedScore = score;
1017 if (bestPairScore < 0.f || score < bestPairScore) {
1018 bestPairScore = score;
1019 bestPair[0] = c0.index;
1020 bestPair[1] = c1.index;
1021 timeTOFMUS = float(pairTimeNS * 1e-3);
1025 scoreTOFPair = bestPairScore;
1026 scoreTOFReversed = bestReversedScore;
1028 if (bestPairScore >= 0.f) {
1029 best[0] = bestPair[0];
1030 best[1] = bestPair[1];
1032 }
else if (best[0] >= 0 && best[0] == best[1]) {
1033 best[bestScore[0] <= bestScore[1] ? 1 : 0] = -1;
1035 for (
int leg = 0; leg < 2; leg++) {
1036 if (best[leg] < 0) {
1040 if (matched.count(best[leg])) {
1041 for (
auto& cl : out) {
1042 if (cl.leg == leg && cl.channel ==
c.getMainContributingChannel() && cl.timeRaw ==
c.getTimeRaw()) {
1047 auto& dbg = mDbgCosmics[icosm];
1048 for (
size_t j = 0;
j < dbg.tofFlags.size();
j++) {
1049 if (dbg.tofLeg[
j] == leg && dbg.tofChannel[
j] ==
c.getMainContributingChannel() && dbg.tofTimeRaw[
j] ==
c.getTimeRaw()) {
1056 auto& cl = out.emplace_back();
1057 cl.timeRaw =
c.getTimeRaw();
1058 cl.tot =
c.getTot();
1059 cl.channel =
c.getMainContributingChannel();
1063 writeDebugTOF(
c, icosm, leg,
flags);
1075 constexpr int ELossGain = 1;
1076 constexpr int ELossLoss = -1;
1079 const float timeTB = timeMUS / mTPCTBinMUS;
1081 bottom.setPID(o2::track::PID::Muon,
true);
1082 bottom.resetCovariance();
1083 if (std::abs(mBz) <= 0.01f) {
1092 if (!prop->propagateToDCABxByBz(
origin,
bottom, matchParams.maxStep, matchParams.matCorr,
nullptr,
nullptr, ELossGain)) {
1096 top.setPID(o2::track::PID::Muon,
true);
1100 if (!
top.rotate(
bottom.getAlpha()) || !prop->PropagateToXBxByBz(
top,
bottom.getX(), matchParams.maxSnp, matchParams.maxStep, matchParams.matCorr,
nullptr, ELossLoss)) {
1103 o2::track::TrackParCov::MatrixDSym5 cov5;
1104 const float chi2Match =
bottom.getPredictedChi2(
top, cov5);
1112void 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
1115 constexpr float ReadoutWindowMUS = 3.f;
1116 constexpr float PadLength = 10.f;
1117 constexpr int NLayers = o2::trd::constants::NLAYER;
1118 const auto window = timeWindowMUS(cosmicTime);
1119 const float zTimeTol = 0.5f * (window.second - window.first) / mTPCTBinMUS * mCorrMap->getVDrift();
1121 const auto calibrated =
data.getTRDCalibratedTracklets();
1122 if (calibrated.size() !=
tracklets.size()) {
1123 if (!mTRDMismatchWarned) {
1124 LOGP(warning,
"{} calibrated vs {} raw TRD tracklets: TRD road of cosmics skipped", calibrated.size(),
tracklets.size());
1125 mTRDMismatchWarned =
true;
1134 Candidate
best[2][NLayers];
1135 for (
const auto& trig :
data.getTRDTriggerRecords()) {
1136 const int trigBC = trig.getBCData().differenceInBC(mTFStart);
1137 const float trigMUS = trigBC * o2::constants::lhc::LHCBunchSpacingMUS;
1138 if (trigMUS < window.first - ReadoutWindowMUS || trigMUS > window.second) {
1141 for (
int it = trig.getFirstTracklet(); it < trig.getFirstTracklet() + trig.getNumberOfTracklets(); it++) {
1142 if (matched.count(it)) {
1145 const int detector =
tracklets[it].getDetector();
1146 const int sector = detector / o2::trd::constants::NCHAMBERPERSEC;
1147 const int layer = detector % NLayers;
1148 const auto& point = calibrated[it];
1149 for (
int leg = 0; leg < 2; leg++) {
1152 if (!legs[leg] || !predictOutward(*legs[leg], cosmicTime, sector, point.getX(),
y,
z)) {
1155 const float normY = (point.getY() -
y) / mRoadTRD;
1156 const float normZ = (point.getZ() -
z) / (mRoadTRD + PadLength + zTimeTol);
1157 const float score = std::max(normY * normY, normZ * normZ);
1158 if (score < best[leg][
layer].score) {
1164 for (
int leg = 0; leg < 2; leg++) {
1167 if (cand.tracklet < 0) {
1170 auto& tr = out.emplace_back();
1171 tr.word =
tracklets[cand.tracklet].getTrackletWord();
1172 tr.trigBC = cand.trigBC;
1177 const auto& point = calibrated[cand.tracklet];
1178 const int sector =
tracklets[cand.tracklet].getDetector() / o2::trd::constants::NCHAMBERPERSEC;
1181 predictOutward(*legs[leg], cosmicTime, sector, point.getX(),
y,
z);
1182 auto& dbg = mDbgCosmics[icosm];
1183 dbg.trdLeg.push_back(leg);
1184 dbg.trdLayer.push_back(
layer);
1185 dbg.trdX.push_back(point.getX());
1186 dbg.trdY.push_back(point.getY());
1187 dbg.trdZ.push_back(point.getZ());
1188 dbg.trdDy.push_back(point.getY() -
y);
1189 dbg.trdDz.push_back(point.getZ() -
z);
1190 dbg.trdTrigMUS.push_back(cand.trigBC *
float(o2::constants::lhc::LHCBunchSpacingMUS));
1196void CosmicsClusterCollectorSpec::roadITS(
const RecoContainer&
data,
const o2::dataformats::TrackCosmics& cosm,
const CosmicTime& cosmicTime,
int legsSide,
int icosm, std::vector<o2::dataformats::CosmicITSCluster>& out,
1197 std::vector<ITSPattRequest>& requests,
const std::unordered_set<int>& matched)
const
1199 if (
data.getITSPerLayer() || mITSChipCentres.empty()) {
1203 constexpr float MaxRadius = 45.f;
1204 constexpr float ChipHalfDiag = 1.7f;
1206 if (!
par.rotateParam(
par.getPhi())) {
1209 std::vector<o2::math_utils::Point3D<float>> points;
1210 for (
float x = -MaxRadius - 5.f;
x <= MaxRadius + 5.f;
x += 1.f) {
1212 const auto point =
par.getXYZGloAt(
x, mBz, ok);
1214 points.push_back(point);
1217 if (points.size() < 2) {
1221 auto closest = [&points](
float x,
float y,
float& dist2,
float& zTraj) {
1223 for (
size_t i = 0;
i + 1 < points.size();
i++) {
1224 const float segX = points[
i + 1].X() - points[
i].X();
1225 const float segY = points[
i + 1].Y() - points[
i].Y();
1226 const float len2 = segX * segX + segY * segY;
1227 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;
1228 const float dx =
x - (points[
i].X() + frac * segX);
1229 const float dy =
y - (points[
i].Y() + frac * segY);
1230 if (dx * dx + dy * dy < dist2) {
1231 dist2 = dx * dx + dy * dy;
1232 zTraj = points[
i].Z() + frac * (points[
i + 1].Z() - points[
i].Z());
1236 float minR2 = 1e10f;
1238 for (
const auto& point : points) {
1239 const float r2 = point.X() * point.X() + point.Y() * point.Y();
1245 if (minR2 > MaxRadius * MaxRadius) {
1248 std::vector<bool> candidateChip(mITSChipCentres.size(),
false);
1249 bool anyChip =
false;
1250 const float chipCut2 = (mRoadITS + ChipHalfDiag) * (mRoadITS + ChipHalfDiag);
1251 for (
size_t chip = 0; chip < mITSChipCentres.size(); chip++) {
1254 closest(mITSChipCentres[chip].X(), mITSChipCentres[chip].Y(), dist2, zTraj);
1255 if (dist2 < chipCut2) {
1256 candidateChip[chip] =
true;
1263 const auto window = timeWindowMUS(cosmicTime);
1264 const float zTimeTol = 0.5f * (window.second - window.first) / mTPCTBinMUS * mCorrMap->getVDrift();
1266 const float zShift = legsSide * (cosmicTime.tb - cosm.
getTimeMUS().getTimeStamp() / mTPCTBinMUS) * mCorrMap->getVDrift();
1270 constexpr int NLayers = 7;
1271 constexpr int NLayersIB = 3;
1272 constexpr int MaxHitsIB = 5;
1278 Candidate
best[2][NLayers][MaxHitsIB];
1281 for (
const auto& rof :
data.getITSClustersROFRecords()) {
1282 const int rofBC = rof.getBCData().differenceInBC(mTFStart);
1283 const float rofMUS = rofBC * o2::constants::lhc::LHCBunchSpacingMUS;
1284 if (rofMUS + rofLengthMUS < window.first || rofMUS > window.second) {
1287 for (
int idx = rof.getFirstEntry();
idx < rof.getFirstEntry() + rof.getNEntries();
idx++) {
1289 if (!candidateChip[
c.getSensorID()] || matched.count(idx)) {
1298 const auto global = geom->getMatrixL2G(
c.getSensorID()) * local;
1301 closest(global.X(), global.Y(), dist2, zTraj);
1302 const float normZ = (global.Z() - zTraj - zShift) / (mRoadITS + zTimeTol);
1303 const float score = std::max(dist2 / (mRoadITS * mRoadITS), normZ * normZ);
1304 const int half = global.Y() < pcaY ? 0 : 1;
1305 const int layer = geom->getLayer(
c.getSensorID());
1306 if (layer < 0 || layer >= NLayers) {
1310 int slot = (
layer < NLayersIB ? MaxHitsIB : 1) - 1;
1311 if (!(score < candidates[slot].score)) {
1314 for (; slot > 0 && score < candidates[slot - 1].score; slot--) {
1315 candidates[slot] = candidates[slot - 1];
1317 candidates[slot] = {
idx, rofBC, score};
1323 if (candidate.index < 0) {
1326 const auto&
c =
clusters[candidate.index];
1327 auto& cl = out.emplace_back();
1328 cl.chipID =
c.getSensorID();
1329 cl.row =
c.getRow();
1330 cl.col =
c.getCol();
1331 cl.pattID =
c.getPatternID();
1332 cl.rofBC = candidate.rofBC;
1336 requests.push_back({icosm,
int(out.size()) - 1, candidate.index});
1343void CosmicsClusterCollectorSpec::fillITSPatterns(
const RecoContainer&
data, std::vector<ITSPattRequest>& requests, std::vector<o2::dataformats::TrackCosmicsExtended>& cosmics)
const
1347 if (!mNoDictWarned) {
1348 LOGP(warning,
"No ITS cluster dictionary: patterns of ITS clusters of cosmics are not stored");
1349 mNoDictWarned =
true;
1353 std::sort(requests.begin(), requests.end(), [](
const ITSPattRequest&
a,
const ITSPattRequest&
b) { return a.index < b.index; });
1355 auto pattIt =
data.getITSClustersPatterns().begin();
1357 for (
int k = 0; k < (
int)
clusters.size() &&
ir < requests.size(); k++) {
1358 const auto pattID =
clusters[k].getPatternID();
1362 const auto start = pattIt;
1364 for (;
ir < requests.size() && requests[
ir].
index == k;
ir++) {
1365 auto& cosm = cosmics[requests[
ir].cosmic];
1366 cosm.clITS[requests[
ir].cluster].pattEntry = cosm.itsPatterns.size();
1367 cosm.itsPatterns.insert(cosm.itsPatterns.end(),
start, pattIt);
1372void CosmicsClusterCollectorSpec::addTRD(
const RecoContainer&
data,
GTrackID gid, uint8_t leg, std::vector<o2::dataformats::CosmicTRDTracklet>& out, std::unordered_set<int>& matched)
const
1376 const auto trigs =
data.getTRDTriggerRecords();
1378 const int it = trk.getTrackletIndex(
layer);
1382 auto& tr = out.emplace_back();
1383 tr.word =
tracklets[it].getTrackletWord();
1388 auto trig = std::upper_bound(trigs.begin(), trigs.end(), it, [](
int v,
const o2::trd::TriggerRecord& t) { return v < t.getFirstTracklet(); });
1389 if (trig != trigs.begin()) {
1390 tr.trigBC = std::prev(trig)->getBCData().differenceInBC(mTFStart);
1395void CosmicsClusterCollectorSpec::flagDuplicates(std::vector<o2::dataformats::TrackCosmicsExtended>& cosmics)
const
1400 constexpr float MinSharedFraction = 0.3f;
1401 const size_t n = cosmics.size();
1405 std::vector<std::vector<uint64_t>>
keys(
n);
1406 std::vector<int> nAttached(
n, 0);
1407 for (
size_t ic = 0; ic <
n; ic++) {
1408 for (
const auto* legClusters : {&cosmics[ic].clTPCBottom, &cosmics[ic].clTPCTop}) {
1409 for (
const auto&
c : *legClusters) {
1410 keys[ic].push_back((uint64_t(
c.sector) << 56) | (uint64_t(
c.row) << 48) | (uint64_t(
c.cl.timeFlagsPacked) << 16) |
c.cl.padPacked);
1411 nAttached[ic] +=
c.isAttached();
1416 std::vector<int> order(
n);
1417 std::iota(order.begin(), order.end(), 0);
1418 std::stable_sort(order.begin(), order.end(), [&](
int a,
int b) {
1419 const bool timedA = cosmics[a].hasTOFTime();
1420 const bool timedB = cosmics[b].hasTOFTime();
1421 return timedA != timedB ? timedA : nAttached[a] > nAttached[b];
1423 std::vector<int> kept;
1424 for (
int ic : order) {
1425 for (
int ik : kept) {
1426 std::vector<uint64_t> shared;
1429 if (nMin > 0 && shared.size() >= MinSharedFraction * nMin) {
1430 cosmics[ic].duplicateOf = ik;
1434 if (cosmics[ic].duplicateOf < 0) {
1445 const bool absTimeKnown = cosm.
cosmic.
getTimeMUS().getTimeStampError() < mMaxAbsTimeErr;
1446 int nAttached[2] = {0, 0};
1447 int nRoad[2] = {0, 0};
1448 int side[2] = {-2, -2};
1449 std::vector<int> clLeg;
1450 std::vector<int> clFlags;
1451 std::vector<int> clSector;
1452 std::vector<int> clRow;
1453 std::vector<float> clPad;
1454 std::vector<float> clTime;
1455 std::vector<float> clQMax;
1456 std::vector<float> clQTot;
1457 std::vector<float> clX;
1458 std::vector<float> clY;
1459 std::vector<float> clZ;
1460 std::vector<float> clZCos;
1461 std::vector<float> clGx;
1462 std::vector<float> clGy;
1464 const std::vector<o2::dataformats::CosmicTPCCluster>* legClusters[2] = {&cosm.
clTPCBottom, &cosm.
clTPCTop};
1465 for (
int leg = 0; leg < 2; leg++) {
1466 if (legs[leg]->getNClusters() == 0) {
1469 side[leg] = tpcSide(*legs[leg]);
1470 for (
const auto&
c : *legClusters[leg]) {
1472 const float vertexTime =
c.isAbsTime() ? timeCosmic : legs[leg]->getTime0();
1476 mCorrMap->Transform(
c.sector,
c.row,
c.cl.getPad(),
c.cl.getTime(),
x,
y,
z, vertexTime);
1480 mCorrMap->Transform(
c.sector,
c.row,
c.cl.getPad(),
c.cl.getTime(), xCos, yCos, zCos, timeCosmic);
1482 const float sinAlpha = std::sin(
alpha);
1483 const float cosAlpha = std::cos(
alpha);
1484 clLeg.push_back(leg);
1485 clFlags.push_back(
c.flags);
1486 clSector.push_back(
c.sector);
1487 clRow.push_back(
c.row);
1488 clPad.push_back(
c.cl.getPad());
1489 clTime.push_back(
c.cl.getTime());
1490 clQMax.push_back(
c.cl.getQmax());
1491 clQTot.push_back(
c.cl.getQtot());
1495 clZCos.push_back(zCos);
1496 clGx.push_back(
x * cosAlpha -
y * sinAlpha);
1497 clGy.push_back(
x * sinAlpha +
y * cosAlpha);
1498 (
c.isAttached() ? nAttached : nRoad)[leg]++;
1501 std::vector<int> itsLeg;
1502 std::vector<int> itsFlags;
1503 std::vector<int> itsChip;
1504 std::vector<int> itsRow;
1505 std::vector<int> itsCol;
1506 std::vector<int> itsPattID;
1507 std::vector<int> itsHasPatt;
1508 std::vector<int> itsRofBC;
1509 std::vector<float> itsGx;
1510 std::vector<float> itsGy;
1511 std::vector<float> itsGz;
1512 std::vector<float> itsXLoc;
1513 std::vector<float> itsZLoc;
1514 for (
const auto&
c : cosm.clITS) {
1517 if (
c.pattEntry >= 0) {
1520 pattern.acquirePattern(pattIt);
1528 if (!mITSChipCentres.empty()) {
1531 itsLeg.push_back(
c.leg);
1532 itsFlags.push_back(
c.flags);
1533 itsChip.push_back(
c.chipID);
1534 itsRow.push_back(
c.row);
1535 itsCol.push_back(
c.col);
1536 itsPattID.push_back(
c.pattID);
1537 itsHasPatt.push_back(
c.pattEntry >= 0);
1538 itsRofBC.push_back(
c.rofBC);
1539 itsGx.push_back(global.X());
1540 itsGy.push_back(global.Y());
1541 itsGz.push_back(global.Z());
1542 itsXLoc.push_back(local.X());
1543 itsZLoc.push_back(local.Z());
1545 const auto& dbg = mDbgCosmics[icosm];
1547 (*mDebugOut) <<
"cosmics"
1548 <<
"tf=" << mDbgTF <<
"cosm=" << icosm <<
"t=" <<
time.getTimeStamp() <<
"tErr=" <<
time.getTimeStampError() <<
"absTime=" <<
int(absTimeKnown)
1550 <<
"tgl=" << cosm.
cosmic.getTgl() <<
"side0=" <<
side[0] <<
"side1=" <<
side[1] <<
"nAtt0=" << nAttached[0] <<
"nAtt1=" << nAttached[1]
1551 <<
"nRoad0=" << nRoad[0] <<
"nRoad1=" << nRoad[1] <<
"nITS=" <<
int(cosm.
clITS.size()) <<
"nTOF=" <<
int(cosm.
clTOF.size())
1554 <<
"clLeg=" << clLeg <<
"clFlags=" << clFlags <<
"clSector=" << clSector <<
"clRow=" << clRow <<
"clPad=" << clPad <<
"clTime=" << clTime
1555 <<
"clQMax=" << clQMax <<
"clQTot=" << clQTot <<
"clX=" << clX <<
"clY=" << clY <<
"clZ=" << clZ <<
"clZCos=" << clZCos <<
"clGx=" << clGx
1556 <<
"clGy=" << clGy <<
"roadLeg=" << dbg.roadLeg <<
"roadFrame=" << dbg.roadFrame <<
"roadSector=" << dbg.roadSector <<
"roadRow=" << dbg.roadRow
1557 <<
"roadX=" << dbg.roadX <<
"roadY=" << dbg.roadY <<
"roadZ=" << dbg.roadZ <<
"roadZCos=" << dbg.roadZCos <<
"roadGx=" << dbg.roadGx
1558 <<
"roadGy=" << dbg.roadGy <<
"roadSnp=" << dbg.roadSnp <<
"roadTgl=" << dbg.roadTgl <<
"itsLeg=" << itsLeg <<
"itsFlags=" << itsFlags
1559 <<
"itsChip=" << itsChip <<
"itsRow=" << itsRow <<
"itsCol=" << itsCol <<
"itsPattID=" << itsPattID <<
"itsHasPatt=" << itsHasPatt
1560 <<
"itsRofBC=" << itsRofBC <<
"itsGx=" << itsGx <<
"itsGy=" << itsGy <<
"itsGz=" << itsGz <<
"itsXLoc=" << itsXLoc <<
"itsZLoc=" << itsZLoc
1561 <<
"tofLeg=" << dbg.tofLeg <<
"tofChannel=" << dbg.tofChannel <<
"tofFlags=" << dbg.tofFlags <<
"tofTimeRaw=" << dbg.tofTimeRaw
1562 <<
"tofTime=" << dbg.tofTime <<
"tofTot=" << dbg.tofTot <<
"tofX=" << dbg.tofX <<
"tofY=" << dbg.tofY <<
"tofZ=" << dbg.tofZ <<
"tofGx=" << dbg.tofGx
1563 <<
"tofGy=" << dbg.tofGy <<
"trdLeg=" << dbg.trdLeg <<
"trdLayer=" << dbg.trdLayer <<
"trdX=" << dbg.trdX <<
"trdY=" << dbg.trdY <<
"trdZ=" << dbg.trdZ
1564 <<
"trdDy=" << dbg.trdDy <<
"trdDz=" << dbg.trdDz <<
"trdTrigMUS=" << dbg.trdTrigMUS <<
"\n";
1567void CosmicsClusterCollectorSpec::writeDebugTOF(
const o2::tof::Cluster&
c,
int icosm,
int leg, uint8_t
flags)
const
1571 const float sinAlpha = std::sin(
alpha);
1572 const float cosAlpha = std::cos(
alpha);
1573 auto& dbg = mDbgCosmics[icosm];
1574 dbg.tofLeg.push_back(leg);
1575 dbg.tofChannel.push_back(
c.getMainContributingChannel());
1576 dbg.tofFlags.push_back(
flags);
1577 dbg.tofTimeRaw.push_back(
c.getTimeRaw());
1578 dbg.tofTime.push_back(
c.getTime());
1579 dbg.tofTot.push_back(
c.getTot());
1580 dbg.tofX.push_back(
c.getX());
1581 dbg.tofY.push_back(
c.getY());
1582 dbg.tofZ.push_back(
c.getZ());
1583 dbg.tofGx.push_back(
c.getX() * cosAlpha -
c.getY() * sinAlpha);
1584 dbg.tofGy.push_back(
c.getX() * sinAlpha +
c.getY() * cosAlpha);
1601 LOGP(info,
"Cosmics cluster collector: {} cosmics, {} attached and {} road TPC clusters; Cpu: {:.3e} Real: {:.3e} s in {} slots",
1602 mNCosmics, mNClAttached, mNClCorridor, mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1);
1607 if (itsStag && roadDets[DetID::ITS]) {
1608 LOGP(warning,
"Staggered ITS clusters are not supported: ITS road of cosmics disabled");
1609 roadDets &=
~DetID::getMask(DetID::ITS);
1611 auto dataRequest = std::make_shared<DataRequest>();
1612 dataRequest->setITSPerLayer(itsStag);
1613 dataRequest->requestTracks(
src,
false);
1615 dataRequest->requestClusters(
src,
false);
1616 if (roadDets[DetID::ITS]) {
1617 dataRequest->requestITSClusters(
false);
1619 if (roadDets[DetID::TOF]) {
1620 dataRequest->requestTOFClusters(
false);
1622 if (roadDets[DetID::TRD]) {
1623 dataRequest->requestTRDTracklets(
false);
1625 dataRequest->requestCoscmicTracks(useMC);
1626 auto ggRequest = std::make_shared<o2::base::GRPGeomRequest>(
false,
1630 roadDets[DetID::TOF],
1632 dataRequest->inputs,
1636 std::vector<OutputSpec> outputs;
1637 outputs.emplace_back(
"GLO",
"COSMFULL", 0, Lifetime::Timeframe);
1638 outputs.emplace_back(
"GLO",
"COSMFULLTF", 0, Lifetime::Timeframe);
1639 outputs.emplace_back(
"GLO",
"COSMFULLTFID", 0, Lifetime::Timeframe);
1642 "cosmics-cluster-collector",
1645 AlgorithmSpec{adaptFromTask<CosmicsClusterCollectorSpec>(dataRequest, ggRequest, useMC, roadDets)},
1647 {
"corridor-width", VariantType::Float, 1.f, {
"half-width of the road around each leg [cm]"}},
1648 {
"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"}},
1649 {
"max-cosmics-per-tf", VariantType::Int, 100, {
"write at most this many cosmics per TF (with their clusters), the others are dropped"}},
1650 {
"tof-road-width", VariantType::Float, 5.f, {
"half-width of the road at the TOF [cm]"}},
1651 {
"tof-flight-tolerance", VariantType::Float, 2.f, {
"max. deviation of the top/bottom TOF time difference from the muon's flight time [ns]"}},
1652 {
"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]"}},
1653 {
"trd-road-width", VariantType::Float, 5.f, {
"half-width of the road at the TRD [cm] (in z plus the pad length)"}},
1654 {
"its-road-width", VariantType::Float, 1.5f, {
"half-width of the road in the ITS [cm]"}},
1655 {
"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.
std::vector< ConfigParamSpec > Options
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)
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