|
| 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 | +/// \brief write relevant information about MFTsa tracks for reference flow. |
| 13 | + |
| 14 | + |
| 15 | +#include "PWGEM/Dilepton/DataModel/dileptonTables.h" |
| 16 | +#include "PWGEM/Dilepton/Utils/EMTrackUtilities.h" |
| 17 | + |
| 18 | +#include "Common/Core/TableHelper.h" |
| 19 | +#include "Common/Core/fwdtrackUtilities.h" |
| 20 | +// #include "Common/DataModel/CollisionAssociationTables.h" |
| 21 | + |
| 22 | +#include "CCDB/BasicCCDBManager.h" |
| 23 | +#include "CommonConstants/PhysicsConstants.h" |
| 24 | +#include "DataFormatsParameters/GRPMagField.h" |
| 25 | +#include "DataFormatsParameters/GRPObject.h" |
| 26 | +#include "DetectorsBase/GeometryManager.h" |
| 27 | +#include "DetectorsBase/Propagator.h" |
| 28 | +#include "Framework/AnalysisDataModel.h" |
| 29 | +#include "Framework/AnalysisTask.h" |
| 30 | +#include "Framework/runDataProcessing.h" |
| 31 | +#include "GlobalTracking/MatchGlobalFwd.h" |
| 32 | +#include "MCHTracking/TrackExtrap.h" |
| 33 | +#include "MCHTracking/TrackParam.h" |
| 34 | +#include "ReconstructionDataFormats/TrackFwd.h" |
| 35 | + |
| 36 | +#include <map> |
| 37 | +#include <string> |
| 38 | +#include <utility> |
| 39 | +#include <vector> |
| 40 | + |
| 41 | +using namespace o2; |
| 42 | +using namespace o2::soa; |
| 43 | +using namespace o2::framework; |
| 44 | +using namespace o2::framework::expressions; |
| 45 | +using namespace o2::constants::physics; |
| 46 | +using namespace o2::aod::fwdtrackutils; |
| 47 | +using namespace o2::aod::pwgem::dilepton::utils::emtrackutil; |
| 48 | + |
| 49 | +struct skimmerPrimaryMFTTrack { |
| 50 | + using MyCollisions = soa::Join<aod::Collisions, aod::EvSels, aod::EMEvSels, aod::EMEoIs>; |
| 51 | + using MyCollisionsWithSWT = soa::Join<MyCollisions, aod::EMSWTriggerBitsTMP>; |
| 52 | + using MyCollisionsMC = soa::Join<MyCollisions, aod::McCollisionLabels>; |
| 53 | + |
| 54 | + using MyTracks = aod::MFTTracks; |
| 55 | + using MyTrack = MyTracks::iterator; |
| 56 | + using MyTracksMC = soa::Join<aod::MFTTracks, aod::McMFTTrackLabels>; |
| 57 | + using MyTrackMC = MyTracksMC::iterator; |
| 58 | + |
| 59 | + SliceCache cache; |
| 60 | + Preslice<aod::MFTTracks> perCol = o2::aod::fwdtrack::collisionId; |
| 61 | + Produces<aod::EMPrimaryTracks> emprimarytracks; |
| 62 | + |
| 63 | + // Configurables |
| 64 | + Configurable<std::string> ccdburl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"}; |
| 65 | + Configurable<std::string> grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"}; |
| 66 | + Configurable<std::string> geoPath{"geoPath", "GLO/Config/GeometryAligned", "Path of the geometry file"}; |
| 67 | + |
| 68 | + Configurable<bool> fillQAHistogram{"fillQAHistogram", true, "flag to fill QA histograms"}; |
| 69 | + |
| 70 | + Configurable<float> cfgPtMin{"cfgPtMin", 0.2, "min pt for MFTsa track"}; |
| 71 | + Configurable<float> cfgPtMax{"cfgPtMax", 1e+10, "max pt for MFTsa track"}; |
| 72 | + Configurable<float> cfgEtaMin{"cfgEtaMin", -4, "min eta acceptance"}; |
| 73 | + Configurable<float> cfgEtaMax{"cfgEtaMax", -2, "max eta acceptance"}; |
| 74 | + |
| 75 | + // for z shift for propagation |
| 76 | + Configurable<bool> cfgApplyZShiftFromCCDB{"cfgApplyZShiftFromCCDB", false, "flag to apply z shift from CCDB"}; |
| 77 | + Configurable<std::string> cfgZShiftPath{"cfgZShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for z shift to apply to forward tracks"}; |
| 78 | + Configurable<float> cfgManualZShift{"cfgManualZShift", 0, "manual z-shift for propagation of global muon to PV"}; |
| 79 | + |
| 80 | + HistogramRegistry fRegistry{"output", {}, OutputObjHandlingPolicy::AnalysisObject, false, false}; |
| 81 | + |
| 82 | + int mRunNumber = 0; |
| 83 | + float mBz = 0; |
| 84 | + float mZShift = 0; |
| 85 | + Service<o2::ccdb::BasicCCDBManager> ccdb; |
| 86 | + o2::ccdb::CcdbApi ccdbApi; |
| 87 | + |
| 88 | + void init(InitContext&) |
| 89 | + { |
| 90 | + mRunNumber = 0; |
| 91 | + mBz = 0; |
| 92 | + mZShift = 0; |
| 93 | + |
| 94 | + ccdb->setURL(ccdburl); |
| 95 | + ccdb->setCaching(true); |
| 96 | + ccdb->setLocalObjectValidityChecking(); |
| 97 | + ccdb->setFatalWhenNull(false); |
| 98 | + ccdbApi.init(ccdburl); |
| 99 | + |
| 100 | + if (fillQAHistogram) { |
| 101 | + fRegistry.add("MFT/hPt", "pT;p_{T} (GeV/c)", kTH1F, {{100, 0.0f, 10}}, false); |
| 102 | + fRegistry.add("MFT/hPtEta", "pT vs. #eta;#eta;p_{T} (GeV/c)", kTH2F, {{200, -4.f, -2.f}, {100, 0.0f, 10}}, false); |
| 103 | + fRegistry.add("MFT/hQoverPt", "q/pT;q/p_{T} (GeV/c)^{-1}", kTH1F, {{2000, -10, 10}}, false); |
| 104 | + fRegistry.add("MFT/hEtaPhi", "#eta vs. #varphi;#varphi (rad.);#eta", kTH2F, {{180, 0, 2 * M_PI}, {200, -4.0f, -2.0f}}, false); |
| 105 | + fRegistry.add("MFT/hDCAxy2D", "DCA x vs. y;DCA_{x} (cm);DCA_{y} (cm)", kTH2F, {{200, -0.1f, 0.1f}, {200, -0.1f, 0.1f}}, false); |
| 106 | + fRegistry.add("MFT/hDCAxy", "DCA xy;DCA_{xy} (cm)", kTH1F, {{100, 0, 0.1f}}, false); |
| 107 | + fRegistry.add("MFT/hDCAz", "DCA z;DCA_{z} (cm)", kTH1F, {{100, -0.05f, 0.05f}}, false); |
| 108 | + fRegistry.add("MFT/hDCAxyz", "DCA xy vs. z;DCA_{xy} (cm);DCA_{z} (cm)", kTH2F, {{100, 0, 0.1f}, {100, -0.05f, 0.05f}}, false); |
| 109 | + fRegistry.add("MFT/hNclsMFT", "number of MFT clusters", kTH1F, {{11, -0.5, 10.5}}, false); |
| 110 | + fRegistry.add("MFT/hChi2MFT", "chi2/ndf;chi2/ndf", kTH1F, {{100, 0, 10}}, false); |
| 111 | + fRegistry.add("MFT/hDCAx_PosZ", "DCAx vs. posZ;Z_{vtx} (cm);DCA_{x} (cm)", kTH2F, {{200, -10, +10}, {200, -0.1, +0.1}}, false); |
| 112 | + fRegistry.add("MFT/hDCAy_PosZ", "DCAy vs. posZ;Z_{vtx} (cm);DCA_{y} (cm)", kTH2F, {{200, -10, +10}, {200, -0.1, +0.1}}, false); |
| 113 | + fRegistry.add("MFT/hDCAx_Phi", "DCAx vs. #varphi;#varphi (rad.);DCA_{x} (cm)", kTH2F, {{180, 0, 2 * M_PI}, {200, -0.1, +0.1}}, false); |
| 114 | + fRegistry.add("MFT/hDCAy_Phi", "DCAy vs. #varphi;#varphi (rad.);DCA_{y} (cm)", kTH2F, {{180, 0, 2 * M_PI}, {200, -0.1, +0.1}}, false); |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + void initCCDB(aod::BCsWithTimestamps::iterator const& bc) |
| 119 | + { |
| 120 | + if (mRunNumber == bc.runNumber()) { |
| 121 | + return; |
| 122 | + } |
| 123 | + mRunNumber = bc.runNumber(); |
| 124 | + LOGF(info, "mRunNumber = %d", mRunNumber); |
| 125 | + std::map<std::string, std::string> metadata; |
| 126 | + auto soreor = o2::ccdb::BasicCCDBManager::getRunDuration(ccdbApi, mRunNumber); |
| 127 | + auto ts = soreor.first; |
| 128 | + auto grpmag = ccdbApi.retrieveFromTFileAny<o2::parameters::GRPMagField>(grpmagPath, metadata, ts); |
| 129 | + o2::base::Propagator::initFieldFromGRP(grpmag); |
| 130 | + if (!o2::base::GeometryManager::isGeometryLoaded()) { |
| 131 | + ccdb->get<TGeoManager>(geoPath); |
| 132 | + } |
| 133 | + o2::mch::TrackExtrap::setField(); |
| 134 | + const double centerMFT[3] = {0, 0, -61.4}; |
| 135 | + o2::field::MagneticField* field = static_cast<o2::field::MagneticField*>(TGeoGlobalMagField::Instance()->GetField()); |
| 136 | + mBz = field->getBz(centerMFT); // Get field at centre of MFT |
| 137 | + LOGF(info, "Bz at center of MFT = %f kZG", mBz); |
| 138 | + |
| 139 | + if (cfgApplyZShiftFromCCDB) { |
| 140 | + auto* zShift = ccdb->getForTimeStamp<std::vector<float>>(cfgZShiftPath, bc.timestamp()); |
| 141 | + if (zShift != nullptr && !zShift->empty()) { |
| 142 | + LOGF(info, "reading z shift %f from %s", (*zShift)[0], cfgZShiftPath.value); |
| 143 | + mZShift = (*zShift)[0]; |
| 144 | + } else { |
| 145 | + LOGF(info, "z shift is not found in ccdb path %s. set to 0 cm", cfgZShiftPath.value); |
| 146 | + mZShift = 0; |
| 147 | + } |
| 148 | + } else { |
| 149 | + LOGF(info, "z shift is manually set to %f cm", cfgManualZShift.value); |
| 150 | + mZShift = cfgManualZShift; |
| 151 | + } |
| 152 | + } |
| 153 | + |
| 154 | + template <bool isMC, typename TCollision, typename TTrack> |
| 155 | + bool checkTrack(TCollision const&, TTrack const& track) |
| 156 | + { |
| 157 | + if constexpr (isMC) { |
| 158 | + if (!track.has_mcParticle()) { |
| 159 | + return false; |
| 160 | + } |
| 161 | + } |
| 162 | + |
| 163 | + return true; |
| 164 | + } |
| 165 | + |
| 166 | + template <typename TCollision, typename TTrack> |
| 167 | + void fillTrackTable(TCollision const& collision, TTrack const& mfttrack) |
| 168 | + { |
| 169 | + // propagate MFTsa track to PV |
| 170 | + std::array<double, 3> dcaInfOrig{999.f, 999.f, 999.f}; |
| 171 | + std::vector<double> v1; // Temporary null vector for the computation of the covariance matrix |
| 172 | + SMatrix55 tcovs(v1.begin(), v1.end()); |
| 173 | + SMatrix5 tpars(mfttrack.x(), mfttrack.y(), mfttrack.phi(), mfttrack.tgl(), mfttrack.signed1Pt()); |
| 174 | + o2::track::TrackParCovFwd trackPar{mfttrack.z() + mZShift, tpars, tcovs, mfttrack.chi2()}; |
| 175 | + trackPar.propagateToDCAhelix(mBz, {collision.posX(), collision.posY(), collision.posZ()}, dcaInfOrig); |
| 176 | + v1.clear(); |
| 177 | + v1.shrink_to_fit(); |
| 178 | + float dcaX = dcaInfOrig[0]; |
| 179 | + float dcaY = dcaInfOrig[1]; |
| 180 | + float dcaZ = dcaInfOrig[2]; |
| 181 | + float dcaXY = std::sqrt(dcaX * dcaX + dcaY * dcaY); |
| 182 | + |
| 183 | + float pt = trackPar.getPt(); |
| 184 | + float eta = trackPar.getEta(); |
| 185 | + float phi = trackPar.getPhi(); |
| 186 | + o2::math_utils::bringTo02Pi(phi); |
| 187 | + |
| 188 | + if (pt < cfgPtMin || cfgPtMax < pt) { |
| 189 | + return; |
| 190 | + } |
| 191 | + if (eta < cfgEtaMin || cfgEtaMax < eta) { |
| 192 | + return; |
| 193 | + } |
| 194 | + |
| 195 | + uint16_t trackBit = 0; |
| 196 | + int ndf = 2 * mfttrack.nClusters() - 5; |
| 197 | + |
| 198 | + // As minimal cuts, following cuts are applied. The cut values are hardcoded on the purpose for consistent bit operation. |
| 199 | + // Ncls MFT >= 5 |
| 200 | + // chi2/ndf MFT < 5 |
| 201 | + // |dcaXY| < 0.06 cm |
| 202 | + |
| 203 | + if (mfttrack.nClusters() < 6 || mfttrack.chi2() / ndf > 5.f || std::fabs(dcaXY) > 0.05) { |
| 204 | + return; |
| 205 | + } |
| 206 | + |
| 207 | + if (mfttrack.nClusters() >= 7) { |
| 208 | + trackBit |= static_cast<uint16_t>(RefMFTTrackBit::kNclsMFT7); |
| 209 | + } |
| 210 | + if (mfttrack.nClusters() >= 8) { |
| 211 | + trackBit |= static_cast<uint16_t>(RefMFTTrackBit::kNclsMFT8); |
| 212 | + } |
| 213 | + |
| 214 | + if (mfttrack.chi2() / ndf < 4.f) { |
| 215 | + trackBit |= static_cast<uint16_t>(RefMFTTrackBit::kChi2MFT4); |
| 216 | + } |
| 217 | + if (mfttrack.chi2() / ndf < 3.f) { |
| 218 | + trackBit |= static_cast<uint16_t>(RefMFTTrackBit::kChi2MFT3); |
| 219 | + } |
| 220 | + |
| 221 | + if (std::fabs(dcaXY) < 0.04) { |
| 222 | + trackBit |= static_cast<uint16_t>(RefMFTTrackBit::kDCAxy004cm); |
| 223 | + } |
| 224 | + if (std::fabs(dcaXY) < 0.03) { |
| 225 | + trackBit |= static_cast<uint16_t>(RefMFTTrackBit::kDCAxy003cm); |
| 226 | + } |
| 227 | + if (std::fabs(dcaXY) < 0.02) { |
| 228 | + trackBit |= static_cast<uint16_t>(RefMFTTrackBit::kDCAxy002cm); |
| 229 | + } |
| 230 | + if (std::fabs(dcaXY) < 0.01) { |
| 231 | + trackBit |= static_cast<uint16_t>(RefMFTTrackBit::kDCAxy001cm); |
| 232 | + } |
| 233 | + |
| 234 | + emprimarytracks(collision.globalIndex(), mfttrack.globalIndex(), mfttrack.sign() / pt, eta, phi, trackBit); |
| 235 | + |
| 236 | + if (fillQAHistogram) { |
| 237 | + fRegistry.fill(HIST("MFT/hPt"), pt); |
| 238 | + fRegistry.fill(HIST("MFT/hPtEta"), eta, pt); |
| 239 | + fRegistry.fill(HIST("MFT/hQoverPt"), mfttrack.sign() / pt); |
| 240 | + fRegistry.fill(HIST("MFT/hEtaPhi"), phi, eta); |
| 241 | + fRegistry.fill(HIST("MFT/hDCAxy2D"), dcaX, dcaY); |
| 242 | + fRegistry.fill(HIST("MFT/hDCAxy"), dcaXY); |
| 243 | + fRegistry.fill(HIST("MFT/hDCAz"), dcaZ); |
| 244 | + fRegistry.fill(HIST("MFT/hDCAxyz"), dcaXY, dcaZ); |
| 245 | + fRegistry.fill(HIST("MFT/hNclsMFT"), mfttrack.nClusters()); |
| 246 | + fRegistry.fill(HIST("MFT/hChi2MFT"), mfttrack.chi2() / ndf); |
| 247 | + fRegistry.fill(HIST("MFT/hDCAx_PosZ"), collision.posZ(), dcaX); |
| 248 | + fRegistry.fill(HIST("MFT/hDCAy_PosZ"), collision.posZ(), dcaY); |
| 249 | + fRegistry.fill(HIST("MFT/hDCAx_Phi"), phi, dcaX); |
| 250 | + fRegistry.fill(HIST("MFT/hDCAy_Phi"), phi, dcaY); |
| 251 | + } |
| 252 | + } |
| 253 | + |
| 254 | + // ---------- for data ---------- |
| 255 | + |
| 256 | + void processRec(MyCollisions const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks) |
| 257 | + { |
| 258 | + |
| 259 | + for (const auto& collision : collisions) { |
| 260 | + auto bc = collision.template foundBC_as<aod::BCsWithTimestamps>(); |
| 261 | + initCCDB(bc); |
| 262 | + if (!collision.isSelected()) { |
| 263 | + continue; |
| 264 | + } |
| 265 | + if (!collision.isEoI()) { // events with at least 1 lepton for data reduction. |
| 266 | + continue; |
| 267 | + } |
| 268 | + |
| 269 | + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); |
| 270 | + for (const auto& track : tracks_per_coll) { |
| 271 | + if (!checkTrack<false>(collision, track)) { |
| 272 | + continue; |
| 273 | + } |
| 274 | + fillTrackTable(collision, track); |
| 275 | + } |
| 276 | + |
| 277 | + } // end of collision loop |
| 278 | + } |
| 279 | + PROCESS_SWITCH(skimmerPrimaryMFTTrack, processRec, "process reconstructed info only", true); // standalone |
| 280 | + |
| 281 | + void processRec_SWT(MyCollisionsWithSWT const& collisions, aod::BCsWithTimestamps const&, MyTracks const& tracks) |
| 282 | + { |
| 283 | + |
| 284 | + for (const auto& collision : collisions) { |
| 285 | + auto bc = collision.template foundBC_as<aod::BCsWithTimestamps>(); |
| 286 | + initCCDB(bc); |
| 287 | + |
| 288 | + if (!collision.isSelected()) { |
| 289 | + continue; |
| 290 | + } |
| 291 | + if (!collision.isEoI()) { |
| 292 | + continue; |
| 293 | + } |
| 294 | + if (collision.swtaliastmp_raw() == 0) { |
| 295 | + continue; |
| 296 | + } |
| 297 | + |
| 298 | + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); |
| 299 | + for (const auto& track : tracks_per_coll) { |
| 300 | + if (!checkTrack<false>(collision, track)) { |
| 301 | + continue; |
| 302 | + } |
| 303 | + fillTrackTable(collision, track); |
| 304 | + } |
| 305 | + |
| 306 | + } // end of collision loop |
| 307 | + } |
| 308 | + PROCESS_SWITCH(skimmerPrimaryMFTTrack, processRec_SWT, "process reconstructed info only", false); // standalone with swt |
| 309 | + |
| 310 | + // ---------- for MC ---------- |
| 311 | + |
| 312 | + void processMC(MyCollisionsMC const& collisions, aod::McCollisions const&, aod::BCsWithTimestamps const&, MyTracksMC const& tracks) |
| 313 | + { |
| 314 | + |
| 315 | + for (const auto& collision : collisions) { |
| 316 | + if (!collision.has_mcCollision()) { |
| 317 | + continue; |
| 318 | + } |
| 319 | + auto bc = collision.template foundBC_as<aod::BCsWithTimestamps>(); |
| 320 | + initCCDB(bc); |
| 321 | + |
| 322 | + if (!collision.isSelected()) { |
| 323 | + continue; |
| 324 | + } |
| 325 | + if (!collision.isEoI()) { // events with at least 1 lepton for data reduction. |
| 326 | + continue; |
| 327 | + } |
| 328 | + |
| 329 | + auto tracks_per_coll = tracks.sliceBy(perCol, collision.globalIndex()); |
| 330 | + for (const auto& track : tracks_per_coll) { |
| 331 | + if (!checkTrack<true>(collision, track)) { |
| 332 | + continue; |
| 333 | + } |
| 334 | + fillTrackTable(collision, track); |
| 335 | + } |
| 336 | + } // end of collision loop |
| 337 | + } |
| 338 | + PROCESS_SWITCH(skimmerPrimaryMFTTrack, processMC, "process reconstructed and MC info ", false); |
| 339 | +}; |
| 340 | + |
| 341 | +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) |
| 342 | +{ |
| 343 | + return WorkflowSpec{adaptAnalysisTask<skimmerPrimaryMFTTrack>(cfgc, TaskName{"skimmer-primary-mfttrack"})}; |
| 344 | +} |
0 commit comments