|
| 1 | +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. |
| 2 | +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. |
| 3 | +// All rights not expressly granted are reserved. |
| 4 | +// |
| 5 | +// This software is distributed under the terms of the GNU General Public |
| 6 | +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". |
| 7 | +// |
| 8 | +// In applying this license CERN does not waive the privileges and immunities |
| 9 | +// granted to it by virtue of its status as an Intergovernmental Organization |
| 10 | +// or submit itself to any jurisdiction. |
| 11 | + |
| 12 | +/// \file muonEfficiencyProducer.cxx |
| 13 | +/// \brief Compact forward-muon skim for offline MCH and MCH-MID efficiency studies |
| 14 | +/// \author Nazar Burmasov (JINR) |
| 15 | + |
| 16 | +#include <CCDB/BasicCCDBManager.h> |
| 17 | +#include <DataFormatsParameters/AggregatedRunInfo.h> |
| 18 | +#include <DataFormatsParameters/GRPMagField.h> |
| 19 | +#include <DetectorsBase/GeometryManager.h> |
| 20 | +#include <DetectorsBase/Propagator.h> |
| 21 | +#include <Framework/ASoA.h> |
| 22 | +#include <Framework/AnalysisDataModel.h> |
| 23 | +#include <Framework/AnalysisHelpers.h> |
| 24 | +#include <Framework/AnalysisTask.h> |
| 25 | +#include <Framework/Configurable.h> |
| 26 | +#include <Framework/DataTypes.h> |
| 27 | +#include <Framework/InitContext.h> |
| 28 | +#include <Framework/Logger.h> |
| 29 | +#include <Framework/runDataProcessing.h> |
| 30 | +#include <GlobalTracking/MatchGlobalFwd.h> |
| 31 | +#include <MCHTracking/TrackExtrap.h> |
| 32 | +#include <ReconstructionDataFormats/GlobalFwdTrack.h> |
| 33 | + |
| 34 | +#include <Math/MatrixRepresentationsStatic.h> |
| 35 | +#include <Math/SMatrix.h> |
| 36 | +#include <TGeoManager.h> |
| 37 | + |
| 38 | +#include <array> |
| 39 | +#include <cstdint> |
| 40 | +#include <vector> |
| 41 | + |
| 42 | +using namespace o2; |
| 43 | +using namespace o2::framework; |
| 44 | + |
| 45 | +namespace o2::aod::mcheffskim |
| 46 | +{ |
| 47 | +DECLARE_SOA_COLUMN(RunNumber, runNumber, int32_t); |
| 48 | +DECLARE_SOA_COLUMN(ReferenceBC, referenceBC, int64_t); |
| 49 | +DECLARE_SOA_COLUMN(FT0AAmplitude, ft0aAmplitude, float); |
| 50 | +DECLARE_SOA_COLUMN(FT0CAmplitude, ft0cAmplitude, float); |
| 51 | +DECLARE_SOA_COLUMN(FV0AAmplitude, fv0aAmplitude, float); |
| 52 | +DECLARE_SOA_COLUMN(CollisionId, collisionId, int32_t); // -1 for ambiguous tracks |
| 53 | +DECLARE_SOA_COLUMN(Pt, pt, float); |
| 54 | +DECLARE_SOA_COLUMN(Eta, eta, float); |
| 55 | +DECLARE_SOA_COLUMN(Phi, phi, float); |
| 56 | +DECLARE_SOA_COLUMN(Sign, sign, int8_t); |
| 57 | +DECLARE_SOA_COLUMN(RAbs, rAbs, float); |
| 58 | +DECLARE_SOA_COLUMN(PDca, pDca, float); |
| 59 | +DECLARE_SOA_COLUMN(Chi2Ndf, chi2Ndf, float); // -1 if propagation failed |
| 60 | +DECLARE_SOA_COLUMN(NClusters, nClusters, int8_t); |
| 61 | +DECLARE_SOA_COLUMN(MchBitMap, mchBitMap, uint16_t); |
| 62 | +DECLARE_SOA_COLUMN(MidBitMap, midBitMap, uint8_t); |
| 63 | +DECLARE_SOA_COLUMN(MidBoards, midBoards, uint32_t); |
| 64 | +DECLARE_SOA_COLUMN(Chi2MatchMCHMID, chi2MatchMCHMID, float); // -1 for MCH-only tracks |
| 65 | +DECLARE_SOA_COLUMN(TrackTime, trackTime, float); // ns relative to referenceBC |
| 66 | +DECLARE_SOA_COLUMN(TrackTimeRes, trackTimeRes, float); |
| 67 | +} // namespace o2::aod::mcheffskim |
| 68 | + |
| 69 | +namespace o2::aod |
| 70 | +{ |
| 71 | +DECLARE_SOA_TABLE(MchEffBCs, "AOD", "MCHEFFBC", |
| 72 | + o2::soa::Index<>, |
| 73 | + mcheffskim::RunNumber, mcheffskim::ReferenceBC, |
| 74 | + mcheffskim::FT0AAmplitude, mcheffskim::FT0CAmplitude, |
| 75 | + mcheffskim::FV0AAmplitude); |
| 76 | +} // namespace o2::aod |
| 77 | + |
| 78 | +namespace o2::aod::mcheffskim |
| 79 | +{ |
| 80 | +DECLARE_SOA_INDEX_COLUMN(MchEffBC, mchEffBC); // links a muon to the compact BC table |
| 81 | +} // namespace o2::aod::mcheffskim |
| 82 | + |
| 83 | +namespace o2::aod |
| 84 | +{ |
| 85 | +DECLARE_SOA_TABLE(MchEffSkims, "AOD", "MCHEFFSKIM", |
| 86 | + o2::soa::Index<>, mcheffskim::MchEffBCId, |
| 87 | + mcheffskim::CollisionId, |
| 88 | + mcheffskim::Pt, mcheffskim::Eta, mcheffskim::Phi, mcheffskim::Sign, |
| 89 | + mcheffskim::RAbs, mcheffskim::PDca, mcheffskim::Chi2Ndf, |
| 90 | + mcheffskim::NClusters, mcheffskim::MchBitMap, |
| 91 | + mcheffskim::MidBitMap, mcheffskim::MidBoards, |
| 92 | + mcheffskim::Chi2MatchMCHMID, |
| 93 | + mcheffskim::TrackTime, mcheffskim::TrackTimeRes); |
| 94 | +} // namespace o2::aod |
| 95 | + |
| 96 | +struct MuonEfficiencyProducer { |
| 97 | + static constexpr float MinEta = -4.f; |
| 98 | + static constexpr float MaxEta = -2.5f; |
| 99 | + static constexpr float NoAmplitude = -1.f; |
| 100 | + static constexpr float MaxFITTime = 30.f; |
| 101 | + |
| 102 | + using Tracks = soa::Join<aod::FwdTracks, aod::FwdTracksCov>; |
| 103 | + using Matrix55 = ROOT::Math::SMatrix<double, 5, 5, ROOT::Math::MatRepSym<double, 5>>; |
| 104 | + using Vector5 = ROOT::Math::SVector<double, 5>; |
| 105 | + |
| 106 | + Produces<aod::MchEffBCs> outputBCs; |
| 107 | + Produces<aod::MchEffSkims> output; |
| 108 | + Service<ccdb::BasicCCDBManager> ccdb{}; |
| 109 | + globaltracking::MatchGlobalFwd matcher; |
| 110 | + int cachedFieldRun = -1; |
| 111 | + |
| 112 | + Configurable<float> minPt{"minPt", 0.4f, "Minimum track pT (Gev/c)"}; |
| 113 | + Configurable<float> minRAbs{"minRAbs", 17.6f, "Minimum absorber-end radius (cm)"}; |
| 114 | + Configurable<float> maxRAbs{"maxRAbs", 89.5f, "Maximum absorber-end radius (cm)"}; |
| 115 | + Configurable<float> maxPDca{"maxPDca", 400.f, "Maximum stored pDCA (GeV cm/c)"}; |
| 116 | + Configurable<float> maxChi2{"maxChi2", 100.f, "Maximum MCH chi2/ndf"}; |
| 117 | + |
| 118 | + void init(InitContext&) |
| 119 | + { |
| 120 | + ccdb->setLocalObjectValidityChecking(); |
| 121 | + } |
| 122 | + |
| 123 | + void setField(int run) |
| 124 | + { |
| 125 | + if (cachedFieldRun == run) { |
| 126 | + return; |
| 127 | + } |
| 128 | + const auto runInfo = parameters::AggregatedRunInfo::buildAggregatedRunInfo(ccdb->instance(), run); |
| 129 | + const auto ts = (runInfo.sor + runInfo.eor) / 2; |
| 130 | + auto* grp = ccdb->getForTimeStamp<parameters::GRPMagField>("GLO/Config/GRPMagField", ts); |
| 131 | + if (!grp) { |
| 132 | + LOGF(fatal, "GRPMagField not found for run %d", run); |
| 133 | + } |
| 134 | + base::Propagator::initFieldFromGRP(grp); |
| 135 | + if (!base::GeometryManager::isGeometryLoaded()) { |
| 136 | + ccdb->get<TGeoManager>("GLO/Config/GeometryAligned"); |
| 137 | + } |
| 138 | + mch::TrackExtrap::setField(); |
| 139 | + cachedFieldRun = run; |
| 140 | + } |
| 141 | + |
| 142 | + struct Kinematics { |
| 143 | + float pt, eta, phi; |
| 144 | + }; |
| 145 | + |
| 146 | + template <typename Track> |
| 147 | + bool propagateMCH(const Track& t, const std::array<float, 3>& vtx, const std::array<float, 2>& vtxCov, Kinematics& k) |
| 148 | + { |
| 149 | + const Vector5 params(t.x(), t.y(), t.phi(), t.tgl(), t.signed1Pt()); |
| 150 | + const std::vector<double> covElements{t.cXX(), t.cXY(), t.cYY(), t.cPhiX(), t.cPhiY(), t.cPhiPhi(), |
| 151 | + t.cTglX(), t.cTglY(), t.cTglPhi(), t.cTglTgl(), |
| 152 | + t.c1PtX(), t.c1PtY(), t.c1PtPhi(), t.c1PtTgl(), t.c1Pt21Pt2()}; |
| 153 | + const Matrix55 cov(covElements.begin(), covElements.end()); |
| 154 | + dataformats::GlobalFwdTrack source; |
| 155 | + source.setParameters(params); |
| 156 | + source.setZ(t.z()); |
| 157 | + source.setCovariances(cov); |
| 158 | + auto mchTrack = matcher.FwdtoMCH(source); |
| 159 | + if (!mch::TrackExtrap::extrapToVertex(mchTrack, vtx[0], vtx[1], vtx[2], vtxCov[0], vtxCov[1])) { |
| 160 | + return false; |
| 161 | + } |
| 162 | + const auto propagated = matcher.MCHtoFwd(mchTrack); |
| 163 | + k = {.pt = static_cast<float>(propagated.getPt()), .eta = static_cast<float>(propagated.getEta()), .phi = static_cast<float>(propagated.getPhi())}; |
| 164 | + return true; |
| 165 | + } |
| 166 | + |
| 167 | + void process(aod::BCs const& bcs, aod::FT0s const& ft0s, aod::FV0As const& fv0as, |
| 168 | + Tracks const& tracks, aod::Collisions const& collisions, |
| 169 | + aod::AmbiguousFwdTracks const& ambiguous) |
| 170 | + { |
| 171 | + if (bcs.size() == 0) { |
| 172 | + return; |
| 173 | + } |
| 174 | + const int run = bcs.begin().runNumber(); |
| 175 | + |
| 176 | + std::vector<float> ft0aByBC(bcs.size(), NoAmplitude); |
| 177 | + std::vector<float> ft0cByBC(bcs.size(), NoAmplitude); |
| 178 | + std::vector<float> fv0aByBC(bcs.size(), NoAmplitude); |
| 179 | + std::vector<int32_t> skimBCIds(bcs.size(), -1); |
| 180 | + for (const auto& ft0 : ft0s) { |
| 181 | + if (ft0.timeA() < MaxFITTime) { |
| 182 | + ft0aByBC[ft0.bcId()] = ft0.sumAmpA(); |
| 183 | + } |
| 184 | + if (ft0.timeC() < MaxFITTime) { |
| 185 | + ft0cByBC[ft0.bcId()] = ft0.sumAmpC(); |
| 186 | + } |
| 187 | + } |
| 188 | + for (const auto& fv0 : fv0as) { |
| 189 | + if (fv0.time() >= MaxFITTime) { |
| 190 | + continue; |
| 191 | + } |
| 192 | + float amplitude = 0.f; |
| 193 | + for (const float a : fv0.amplitude()) { |
| 194 | + if (a > 0.f) { |
| 195 | + amplitude += a; |
| 196 | + } |
| 197 | + } |
| 198 | + fv0aByBC[fv0.bcId()] = amplitude; |
| 199 | + } |
| 200 | + |
| 201 | + std::vector<int32_t> ambiguousBCIds(tracks.size(), -1); |
| 202 | + for (const auto& entry : ambiguous) { |
| 203 | + const auto& ids = entry.bcIds(); |
| 204 | + if (ids.empty()) { |
| 205 | + continue; |
| 206 | + } |
| 207 | + ambiguousBCIds[entry.fwdtrackId()] = *ids.begin(); |
| 208 | + } |
| 209 | + |
| 210 | + for (const auto& t : tracks) { |
| 211 | + const auto type = t.trackType(); |
| 212 | + if (type != aod::fwdtrack::MuonStandaloneTrack && type != aod::fwdtrack::MCHStandaloneTrack) { |
| 213 | + continue; |
| 214 | + } |
| 215 | + const float rAbs = t.rAtAbsorberEnd(); |
| 216 | + if (rAbs < minRAbs || rAbs > maxRAbs || t.pDca() > maxPDca || t.chi2() > maxChi2) { |
| 217 | + continue; |
| 218 | + } |
| 219 | + Kinematics k{.pt = t.pt(), .eta = t.eta(), .phi = t.phi()}; |
| 220 | + std::array<float, 3> vtx{0.f, 0.f, 0.f}; |
| 221 | + std::array<float, 2> vtxCov{0.f, 0.f}; |
| 222 | + int32_t referenceBCId = ambiguousBCIds[t.globalIndex()]; |
| 223 | + if (t.has_collision()) { |
| 224 | + const auto col = collisions.iteratorAt(t.collisionId()); |
| 225 | + vtx = {col.posX(), col.posY(), col.posZ()}; |
| 226 | + vtxCov = {col.covXX(), col.covYY()}; |
| 227 | + referenceBCId = col.bcId(); |
| 228 | + } |
| 229 | + setField(run); |
| 230 | + if (!propagateMCH(t, vtx, vtxCov, k)) { |
| 231 | + continue; |
| 232 | + } |
| 233 | + if (k.eta < MinEta || k.eta > MaxEta) { |
| 234 | + continue; |
| 235 | + } |
| 236 | + if (k.pt < minPt) { |
| 237 | + continue; |
| 238 | + } |
| 239 | + int32_t skimBCId = -1; |
| 240 | + if (referenceBCId >= 0) { |
| 241 | + skimBCId = skimBCIds[referenceBCId]; |
| 242 | + if (skimBCId < 0) { |
| 243 | + outputBCs(run, bcs.iteratorAt(referenceBCId).globalBC(), |
| 244 | + ft0aByBC[referenceBCId], ft0cByBC[referenceBCId], fv0aByBC[referenceBCId]); |
| 245 | + skimBCId = outputBCs.lastIndex(); |
| 246 | + skimBCIds[referenceBCId] = skimBCId; |
| 247 | + } |
| 248 | + } |
| 249 | + output(skimBCId, t.collisionId(), k.pt, k.eta, k.phi, static_cast<int8_t>(t.signed1Pt() > 0 ? 1 : -1), |
| 250 | + rAbs, t.pDca(), t.chi2(), t.nClusters(), t.mchBitMap(), t.midBitMap(), t.midBoards(), |
| 251 | + type == aod::fwdtrack::MuonStandaloneTrack ? t.chi2MatchMCHMID() : -1.f, t.trackTime(), t.trackTimeRes()); |
| 252 | + } |
| 253 | + } |
| 254 | +}; |
| 255 | + |
| 256 | +WorkflowSpec defineDataProcessing(ConfigContext const& context) |
| 257 | +{ |
| 258 | + return WorkflowSpec{adaptAnalysisTask<MuonEfficiencyProducer>(context)}; |
| 259 | +} |
0 commit comments