|
34 | 34 |
|
35 | 35 | #include <Framework/AnalysisDataModel.h> |
36 | 36 |
|
| 37 | +#include <algorithm> |
37 | 38 | #include <array> |
38 | 39 | #include <cmath> |
39 | 40 | #include <cstdint> |
@@ -63,15 +64,15 @@ enum { |
63 | 64 | kAllCutsINELg010, |
64 | 65 | kECend, |
65 | 66 | }; |
66 | | -DECLARE_SOA_INDEX_COLUMN_FULL(Collision, collision, int, Collisions, "_Col"); //! |
67 | | -DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality (Multiplicity) percentile (Default: FT0M) |
68 | | -DECLARE_SOA_COLUMN(Spherocity, spherocity, float); //! Spherocity of the event |
69 | | -DECLARE_SOA_COLUMN(EvtPl, evtPl, float); //! Second harmonic event plane |
70 | | -DECLARE_SOA_COLUMN(EvtPlResAB, evtPlResAB, float); //! Second harmonic event plane resolution of A-B sub events |
71 | | -DECLARE_SOA_COLUMN(EvtPlResAC, evtPlResAC, float); //! Second harmonic event plane resolution of A-C sub events |
72 | | -DECLARE_SOA_COLUMN(EvtPlResBC, evtPlResBC, float); //! Second harmonic event plane resolution of B-C sub events |
73 | | -DECLARE_SOA_COLUMN(BMagField, bMagField, float); //! Magnetic field |
74 | | -DECLARE_SOA_COLUMN(IsRecINELgt0, isRecINELgt0, bool); //! Is reconstructed INEL>0 event |
| 67 | +DECLARE_SOA_COLUMN(CollisionId, collisionId, int); //! Original collision row ID stored as a scalar for standalone derived data |
| 68 | +DECLARE_SOA_COLUMN(Cent, cent, float); //! Centrality (Multiplicity) percentile (Default: FT0M) |
| 69 | +DECLARE_SOA_COLUMN(Spherocity, spherocity, float); //! Spherocity of the event |
| 70 | +DECLARE_SOA_COLUMN(EvtPl, evtPl, float); //! Second harmonic event plane |
| 71 | +DECLARE_SOA_COLUMN(EvtPlResAB, evtPlResAB, float); //! Second harmonic event plane resolution of A-B sub events |
| 72 | +DECLARE_SOA_COLUMN(EvtPlResAC, evtPlResAC, float); //! Second harmonic event plane resolution of A-C sub events |
| 73 | +DECLARE_SOA_COLUMN(EvtPlResBC, evtPlResBC, float); //! Second harmonic event plane resolution of B-C sub events |
| 74 | +DECLARE_SOA_COLUMN(BMagField, bMagField, float); //! Magnetic field |
| 75 | +DECLARE_SOA_COLUMN(IsRecINELgt0, isRecINELgt0, bool); //! Is reconstructed INEL>0 event |
75 | 76 | // MC |
76 | 77 | DECLARE_SOA_COLUMN(IsVtxIn10, isVtxIn10, bool); //! Vtx10 |
77 | 78 | DECLARE_SOA_COLUMN(IsINELgt0, isINELgt0, bool); //! INEL>0 |
@@ -179,9 +180,9 @@ struct ResoTrackFlags { |
179 | 180 |
|
180 | 181 | DECLARE_SOA_INDEX_COLUMN(ResoCollision, resoCollision); |
181 | 182 | DECLARE_SOA_INDEX_COLUMN(ResoCollisionDF, resoCollisionDF); |
182 | | -DECLARE_SOA_INDEX_COLUMN_FULL(Track, track, int, Tracks, "_Trk"); //! |
183 | | -DECLARE_SOA_INDEX_COLUMN_FULL(V0, v0, int, V0s, "_V0"); //! |
184 | | -DECLARE_SOA_INDEX_COLUMN_FULL(Cascade, cascade, int, Cascades, "_Cas"); //! |
| 183 | +DECLARE_SOA_COLUMN(TrackId, trackId, int); //! Original track row ID stored as a scalar for autocorrelation rejection |
| 184 | +DECLARE_SOA_COLUMN(V0Id, v0Id, int); //! Original V0 row ID stored as a scalar |
| 185 | +DECLARE_SOA_COLUMN(CascadeId, cascadeId, int); //! Original cascade row ID stored as a scalar |
185 | 186 | DECLARE_SOA_COLUMN(Pt, pt, float); //! p_t (GeV/c) |
186 | 187 | DECLARE_SOA_COLUMN(Px, px, float); //! p_x (GeV/c) |
187 | 188 | DECLARE_SOA_COLUMN(Py, py, float); //! p_y (GeV/c) |
@@ -507,6 +508,167 @@ struct ResoMicroTrackSelFlag { |
507 | 508 | DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, [](float px, float py) -> float { return RecoDecay::sqrtSumOfSquares(px, py); }); |
508 | 509 | } // namespace resomicrodaughter |
509 | 510 |
|
| 511 | +// Ultra-micro track representation. The momentum components are quantised |
| 512 | +// to 1 MeV/c and only one (pion/kaon/proton) PID flag is retained. |
| 513 | +namespace resoultramicrodaughter |
| 514 | +{ |
| 515 | +/// @brief Compact absolute TPC/TOF n-sigma values for one configured species. |
| 516 | +/// Code 0 represents |n-sigma| < 1.5. Codes 1..14 represent lower-inclusive |
| 517 | +/// 0.25-sigma-wide bins [1.5, 1.75), ..., [4.75, 5.0) and decode to their |
| 518 | +/// lower edges. Code 15 represents |n-sigma| >= 5. Missing TOF information |
| 519 | +/// is carried independently by resodaughter::TrackFlags::kHasTOF. |
| 520 | +struct PidNSigma { |
| 521 | + static constexpr float MinFineNSigma = 1.5f; |
| 522 | + static constexpr float Step = 0.25f; |
| 523 | + static constexpr float MaxNSigma = 5.f; |
| 524 | + static constexpr uint8_t MaxRegularCode = 14; |
| 525 | + static constexpr uint8_t AboveRangeCode = 15; |
| 526 | + |
| 527 | + uint8_t flag; |
| 528 | + |
| 529 | + PidNSigma(float tpcNSigma, float tofNSigma, bool hasTOF) |
| 530 | + { |
| 531 | + const uint8_t tpcEncoded = encodeNSigma(tpcNSigma); |
| 532 | + const uint8_t tofEncoded = hasTOF && std::isfinite(tofNSigma) ? encodeNSigma(tofNSigma) : AboveRangeCode; |
| 533 | + flag = (tpcEncoded << 4) | tofEncoded; |
| 534 | + } |
| 535 | + |
| 536 | + static uint8_t encodeNSigma(float nSigma) |
| 537 | + { |
| 538 | + const float value = std::abs(nSigma); |
| 539 | + if (!std::isfinite(value)) { |
| 540 | + return AboveRangeCode; |
| 541 | + } |
| 542 | + if (value < MinFineNSigma) { |
| 543 | + return 0; |
| 544 | + } |
| 545 | + if (value >= MaxNSigma) { |
| 546 | + return AboveRangeCode; |
| 547 | + } |
| 548 | + const int encoded = 1 + static_cast<int>(std::floor((value - MinFineNSigma) / Step)); |
| 549 | + return static_cast<uint8_t>(std::clamp(encoded, 1, static_cast<int>(MaxRegularCode))); |
| 550 | + } |
| 551 | + |
| 552 | + static float decodeNSigma(uint8_t encoded) |
| 553 | + { |
| 554 | + const uint8_t code = encoded & 0x0F; |
| 555 | + if (code == 0) { |
| 556 | + return 0.f; |
| 557 | + } |
| 558 | + return code == AboveRangeCode ? MaxNSigma : MinFineNSigma + static_cast<float>(code - 1) * Step; |
| 559 | + } |
| 560 | + |
| 561 | + static float getTPCNSigma(uint8_t encoded) |
| 562 | + { |
| 563 | + return decodeNSigma((encoded >> 4) & 0x0F); |
| 564 | + } |
| 565 | + |
| 566 | + static float getTOFNSigma(uint8_t encoded, bool hasTOF) |
| 567 | + { |
| 568 | + return hasTOF ? decodeNSigma(encoded & 0x0F) : NAN; |
| 569 | + } |
| 570 | + |
| 571 | + operator uint8_t() const { return flag; } |
| 572 | +}; |
| 573 | + |
| 574 | +/// @brief Compact absolute DCAxy/DCAz values into two four-bit fields. |
| 575 | +/// Codes 0..14 represent lower-inclusive 0.01 cm-wide bins [0.00, 0.01), |
| 576 | +/// ..., [0.14, 0.15) cm and decode to their lower edges. Code 15 directly |
| 577 | +/// represents |DCA| >= 0.15 cm and decodes to the 0.15 cm marker; no additional |
| 578 | +/// tight-DCA or overflow flag is stored. |
| 579 | +struct DCAEncoding { |
| 580 | + static constexpr float MaxDCA = 0.15f; |
| 581 | + static constexpr float Step = 0.01f; |
| 582 | + static constexpr uint8_t MaxRegularCode = 14; |
| 583 | + static constexpr uint8_t AboveRangeCode = 15; |
| 584 | + |
| 585 | + uint8_t flag = 0; |
| 586 | + |
| 587 | + DCAEncoding() = default; |
| 588 | + DCAEncoding(float dcaXY, float dcaZ) |
| 589 | + : flag(static_cast<uint8_t>((encodeDCA(dcaXY) << 4) | encodeDCA(dcaZ))) |
| 590 | + { |
| 591 | + } |
| 592 | + |
| 593 | + static bool isValid(float dca) |
| 594 | + { |
| 595 | + return std::isfinite(dca); |
| 596 | + } |
| 597 | + |
| 598 | + static uint8_t encodeDCA(float dca) |
| 599 | + { |
| 600 | + const float value = std::abs(dca); |
| 601 | + if (!std::isfinite(value)) { |
| 602 | + return AboveRangeCode; |
| 603 | + } |
| 604 | + if (value >= MaxDCA) { |
| 605 | + return AboveRangeCode; |
| 606 | + } |
| 607 | + const int encoded = static_cast<int>(std::floor(value / Step)); |
| 608 | + return static_cast<uint8_t>(std::clamp(encoded, 0, static_cast<int>(MaxRegularCode))); |
| 609 | + } |
| 610 | + |
| 611 | + static float decodeDCA(uint8_t encoded) |
| 612 | + { |
| 613 | + const uint8_t code = encoded & 0x0F; |
| 614 | + return code == AboveRangeCode ? MaxDCA : static_cast<float>(code) * Step; |
| 615 | + } |
| 616 | + |
| 617 | + static float decodeDCAxy(uint8_t encoded) |
| 618 | + { |
| 619 | + return decodeDCA((encoded >> 4) & 0x0F); |
| 620 | + } |
| 621 | + |
| 622 | + static float decodeDCAz(uint8_t encoded) |
| 623 | + { |
| 624 | + return decodeDCA(encoded & 0x0F); |
| 625 | + } |
| 626 | + |
| 627 | + operator uint8_t() const { return flag; } |
| 628 | +}; |
| 629 | + |
| 630 | +DECLARE_SOA_COLUMN(PidNSigmaFlag, pidNSigmaFlag, uint8_t); //! TPC/TOF PID flag for the configured species |
| 631 | +DECLARE_SOA_COLUMN(TrackSelectionFlags, trackSelectionFlags, uint8_t); //! Packed absolute DCAxy/DCAz values |
| 632 | +DECLARE_SOA_COLUMN(Px1000, px1000, int16_t); //! p_x x 1000 (GeV/c) |
| 633 | +DECLARE_SOA_COLUMN(Py1000, py1000, int16_t); //! p_y x 1000 (GeV/c) |
| 634 | +DECLARE_SOA_COLUMN(Pz1000, pz1000, int16_t); //! p_z x 1000 (GeV/c) |
| 635 | + |
| 636 | +DECLARE_SOA_DYNAMIC_COLUMN(Px, px, |
| 637 | + [](int16_t px1000) { return static_cast<float>(px1000) / 1000.f; }); |
| 638 | +DECLARE_SOA_DYNAMIC_COLUMN(Py, py, |
| 639 | + [](int16_t py1000) { return static_cast<float>(py1000) / 1000.f; }); |
| 640 | +DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, |
| 641 | + [](int16_t pz1000) { return static_cast<float>(pz1000) / 1000.f; }); |
| 642 | +DECLARE_SOA_DYNAMIC_COLUMN(Pt, pt, |
| 643 | + [](int16_t px1000, int16_t py1000) { |
| 644 | + const float px = static_cast<float>(px1000) / 1000.f; |
| 645 | + const float py = static_cast<float>(py1000) / 1000.f; |
| 646 | + return RecoDecay::sqrtSumOfSquares(px, py); |
| 647 | + }); |
| 648 | +DECLARE_SOA_DYNAMIC_COLUMN(Eta, eta, |
| 649 | + [](int16_t px1000, int16_t py1000, int16_t pz1000) { |
| 650 | + return RecoDecay::eta(std::array{static_cast<float>(px1000) / 1000.f, |
| 651 | + static_cast<float>(py1000) / 1000.f, |
| 652 | + static_cast<float>(pz1000) / 1000.f}); |
| 653 | + }); |
| 654 | +DECLARE_SOA_DYNAMIC_COLUMN(Phi, phi, |
| 655 | + [](int16_t px1000, int16_t py1000) { |
| 656 | + return RecoDecay::phi(static_cast<float>(px1000) / 1000.f, |
| 657 | + static_cast<float>(py1000) / 1000.f); |
| 658 | + }); |
| 659 | +DECLARE_SOA_DYNAMIC_COLUMN(TPCNSigma, tpcNSigma, |
| 660 | + [](uint8_t pidNSigmaFlag) { return PidNSigma::getTPCNSigma(pidNSigmaFlag); }); |
| 661 | +DECLARE_SOA_DYNAMIC_COLUMN(TOFNSigma, tofNSigma, |
| 662 | + [](uint8_t pidNSigmaFlag, uint8_t trackFlags) -> float { |
| 663 | + const bool hasTOF = resodaughter::ResoTrackFlags::checkFlag(trackFlags, resodaughter::ResoTrackFlags::kHasTOF); |
| 664 | + return PidNSigma::getTOFNSigma(pidNSigmaFlag, hasTOF); |
| 665 | + }); |
| 666 | +DECLARE_SOA_DYNAMIC_COLUMN(DcaXY, dcaXY, |
| 667 | + [](uint8_t trackSelectionFlags) { return DCAEncoding::decodeDCAxy(trackSelectionFlags); }); |
| 668 | +DECLARE_SOA_DYNAMIC_COLUMN(DcaZ, dcaZ, |
| 669 | + [](uint8_t trackSelectionFlags) { return DCAEncoding::decodeDCAz(trackSelectionFlags); }); |
| 670 | +} // namespace resoultramicrodaughter |
| 671 | + |
510 | 672 | DECLARE_SOA_TABLE(ResoTracks, "AOD", "RESOTRACK", |
511 | 673 | o2::soa::Index<>, |
512 | 674 | resodaughter::ResoCollisionId, |
@@ -582,6 +744,40 @@ DECLARE_SOA_TABLE(ResoMicroTrackTracks, "AOD", "RESOMICROTRACKTRACK", |
582 | 744 | resodaughter::TrackId); |
583 | 745 | using ResoMicroTrackTrack = ResoMicroTrackTracks::iterator; |
584 | 746 |
|
| 747 | +DECLARE_SOA_TABLE(ResoUltraMicroTracks, "AOD", "RESOULTRAMTRK", |
| 748 | + o2::soa::Index<>, |
| 749 | + resodaughter::ResoCollisionId, |
| 750 | + resoultramicrodaughter::Px1000, |
| 751 | + resoultramicrodaughter::Py1000, |
| 752 | + resoultramicrodaughter::Pz1000, |
| 753 | + resoultramicrodaughter::PidNSigmaFlag, |
| 754 | + resoultramicrodaughter::TrackSelectionFlags, |
| 755 | + resodaughter::TrackFlags, |
| 756 | + // Dynamic columns |
| 757 | + resoultramicrodaughter::Px<resoultramicrodaughter::Px1000>, |
| 758 | + resoultramicrodaughter::Py<resoultramicrodaughter::Py1000>, |
| 759 | + resoultramicrodaughter::Pz<resoultramicrodaughter::Pz1000>, |
| 760 | + resoultramicrodaughter::Pt<resoultramicrodaughter::Px1000, resoultramicrodaughter::Py1000>, |
| 761 | + resoultramicrodaughter::Eta<resoultramicrodaughter::Px1000, resoultramicrodaughter::Py1000, resoultramicrodaughter::Pz1000>, |
| 762 | + resoultramicrodaughter::Phi<resoultramicrodaughter::Px1000, resoultramicrodaughter::Py1000>, |
| 763 | + resoultramicrodaughter::TPCNSigma<resoultramicrodaughter::PidNSigmaFlag>, |
| 764 | + resoultramicrodaughter::TOFNSigma<resoultramicrodaughter::PidNSigmaFlag, resodaughter::TrackFlags>, |
| 765 | + resoultramicrodaughter::DcaXY<resoultramicrodaughter::TrackSelectionFlags>, |
| 766 | + resoultramicrodaughter::DcaZ<resoultramicrodaughter::TrackSelectionFlags>, |
| 767 | + resodaughter::PassedITSRefit<resodaughter::TrackFlags>, |
| 768 | + resodaughter::PassedTPCRefit<resodaughter::TrackFlags>, |
| 769 | + resodaughter::IsGlobalTrackWoDCA<resodaughter::TrackFlags>, |
| 770 | + resodaughter::IsGlobalTrack<resodaughter::TrackFlags>, |
| 771 | + resodaughter::IsPrimaryTrack<resodaughter::TrackFlags>, |
| 772 | + resodaughter::IsPVContributor<resodaughter::TrackFlags>, |
| 773 | + resodaughter::HasTOF<resodaughter::TrackFlags>, |
| 774 | + resodaughter::Sign<resodaughter::TrackFlags>); |
| 775 | +using ResoUltraMicroTrack = ResoUltraMicroTracks::iterator; |
| 776 | + |
| 777 | +DECLARE_SOA_TABLE(ResoUltraMicroTrackTracks, "AOD", "RESOULTRAMTRKID", |
| 778 | + resodaughter::TrackId); |
| 779 | +using ResoUltraMicroTrackTrack = ResoUltraMicroTrackTracks::iterator; |
| 780 | + |
585 | 781 | // For DF mixing study |
586 | 782 | DECLARE_SOA_TABLE(ResoTrackDFs, "AOD", "RESOTRACKDF", |
587 | 783 | o2::soa::Index<>, |
|
0 commit comments