|
| 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 SpectatorPlaneTutorial.cxx |
| 13 | +/// \author Noor Koster |
| 14 | +/// \since 11/2025 |
| 15 | +/// \brief This is a tutorial task to show how to use the ZDC q-vectors and the spectator plane resolution. |
| 16 | + |
| 17 | +#include "PWGCF/DataModel/SPTableZDC.h" |
| 18 | + |
| 19 | +#include "Common/Core/EventPlaneHelper.h" |
| 20 | +#include "Common/Core/RecoDecay.h" |
| 21 | +#include "Common/Core/TrackSelection.h" |
| 22 | +#include "Common/DataModel/Centrality.h" |
| 23 | +#include "Common/DataModel/EventSelection.h" |
| 24 | +#include "Common/DataModel/Multiplicity.h" |
| 25 | +#include "Common/DataModel/Qvectors.h" |
| 26 | +#include "Common/DataModel/TrackSelectionTables.h" |
| 27 | + |
| 28 | +#include "CCDB/BasicCCDBManager.h" |
| 29 | +#include "DataFormatsParameters/GRPLHCIFData.h" |
| 30 | +#include "DataFormatsParameters/GRPMagField.h" |
| 31 | +#include "Framework/ASoAHelpers.h" |
| 32 | +#include "Framework/AnalysisTask.h" |
| 33 | +#include "Framework/HistogramRegistry.h" |
| 34 | +#include "Framework/RunningWorkflowInfo.h" |
| 35 | +#include "Framework/runDataProcessing.h" |
| 36 | + |
| 37 | +#include "TF1.h" |
| 38 | +#include "TPDGCode.h" |
| 39 | + |
| 40 | +#include <algorithm> |
| 41 | +#include <map> |
| 42 | +#include <numeric> |
| 43 | +#include <string> |
| 44 | +#include <unordered_map> |
| 45 | +#include <utility> |
| 46 | +#include <vector> |
| 47 | + |
| 48 | +using namespace o2; |
| 49 | +using namespace o2::framework; |
| 50 | +using namespace o2::framework::expressions; |
| 51 | +using namespace o2::aod::rctsel; |
| 52 | +// using namespace o2::analysis; |
| 53 | + |
| 54 | +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable<TYPE> NAME{#NAME, DEFAULT, HELP}; |
| 55 | + |
| 56 | +struct SpectatorPlaneTutorial { |
| 57 | + RCTFlagsChecker rctChecker; |
| 58 | + |
| 59 | + struct : ConfigurableGroup { |
| 60 | + O2_DEFINE_CONFIGURABLE(cfgEvtUseRCTFlagChecker, bool, false, "Evt sel: use RCT flag checker"); |
| 61 | + O2_DEFINE_CONFIGURABLE(cfgEvtRCTFlagCheckerLabel, std::string, "CBT_hadronPID", "Evt sel: RCT flag checker label (CBT, CBT_hadronPID)"); // all Labels can be found in Common/CCDB/RCTSelectionFlags.h |
| 62 | + O2_DEFINE_CONFIGURABLE(cfgEvtRCTFlagCheckerZDCCheck, bool, false, "Evt sel: RCT flag checker ZDC check"); |
| 63 | + O2_DEFINE_CONFIGURABLE(cfgEvtRCTFlagCheckerLimitAcceptAsBad, bool, false, "Evt sel: RCT flag checker treat Limited Acceptance As Bad"); |
| 64 | + } rctFlags; |
| 65 | + |
| 66 | + // settings for CCDB data |
| 67 | + O2_DEFINE_CONFIGURABLE(cfgCCDBdir_QQ, std::string, "Users/c/ckoster/ZDC/LHC23_PbPb_pass5/meanQQ/Default", "ccdb dir for average QQ values in 1% centrality bins"); |
| 68 | + O2_DEFINE_CONFIGURABLE(cfgCCDBdir_SP, std::string, "Users/c/ckoster/ZDC/LHC23_zzh_pass4/SPPlaneRes", "ccdb dir for average event plane resolution in 1% centrality bins"); |
| 69 | + // Confogirable axis |
| 70 | + ConfigurableAxis axisCentrality{"axisCentrality", {20, 0, 100}, "Centrality bins for vn "}; |
| 71 | + |
| 72 | + // Configurables containing vector |
| 73 | + float vtxZ = 10.0; |
| 74 | + float etaMax = 0.8; |
| 75 | + float ptMin = 0.2; |
| 76 | + float ptMax = 10.0; |
| 77 | + float dcaXYMax = 0.2; |
| 78 | + float dcaZMax = 2.0; |
| 79 | + |
| 80 | + Filter collisionFilter = nabs(aod::collision::posZ) < vtxZ; |
| 81 | + Filter trackFilter = nabs(aod::track::eta) < etaMax && aod::track::pt > ptMin&& aod::track::pt < ptMax && ((requireGlobalTrackInFilter()) || (aod::track::isGlobalTrackSDD == (uint8_t) true)) && nabs(aod::track::dcaXY) < dcaXYMax&& nabs(aod::track::dcaZ) < dcaZMax; |
| 82 | + using GeneralCollisions = soa::Join<aod::Collisions, aod::EvSels, aod::Mults, aod::CentFT0Cs>; |
| 83 | + using UnfilteredTracks = soa::Join<aod::Tracks, aod::TracksExtra, aod::TrackSelection, aod::TracksDCA>; |
| 84 | + |
| 85 | + using UsedTracks = soa::Filtered<UnfilteredTracks>; |
| 86 | + using ZDCCollisions = soa::Filtered<soa::Join<GeneralCollisions, aod::SPTableZDC>>; // IMPORTANT: ZDCCollisions must be used to get access to ZDC q-vectors --> PWGCF/DataModel/SPTableZDC.h & PWGCF/Flow/TableProducer/zdcQVectors.cxx |
| 87 | + |
| 88 | + // Connect to ccdb |
| 89 | + Service<ccdb::BasicCCDBManager> ccdb; |
| 90 | + |
| 91 | + HistogramRegistry registry{"registry"}; |
| 92 | + |
| 93 | + void init(InitContext const&) |
| 94 | + { |
| 95 | + ccdb->setURL("http://alice-ccdb.cern.ch"); |
| 96 | + ccdb->setCaching(true); |
| 97 | + ccdb->setLocalObjectValidityChecking(); |
| 98 | + |
| 99 | + int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); |
| 100 | + ccdb->setCreatedNotAfter(now); |
| 101 | + |
| 102 | + AxisSpec axisPhi = {60, 0, constants::math::TwoPI, "#varphi"}; |
| 103 | + AxisSpec axisEta = {64, -1.6, 1.6, "#eta"}; |
| 104 | + AxisSpec axisEtaVn = {8, -.8, .8, "#eta"}; |
| 105 | + AxisSpec axisCent = {90, 0, 90, "Centrality(%)"}; |
| 106 | + AxisSpec axisPhiPlane = {100, -constants::math::PI, constants::math::PI, "#Psi"}; |
| 107 | + AxisSpec axisQQ = {100, -0.2, 0.2, "#LT Q_{X}^{A}Q_{Y}^{C} #GT"}; |
| 108 | + |
| 109 | + std::vector<double> ptbinning = {0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.2, 2.4, 2.6, 2.8, 3, 3.5, 4, 5, 6, 8, 10}; |
| 110 | + AxisSpec axisPt = {ptbinning, "#it{p}_{T} GeV/#it{c}"}; |
| 111 | + |
| 112 | + rctChecker.init(rctFlags.cfgEvtRCTFlagCheckerLabel, rctFlags.cfgEvtRCTFlagCheckerZDCCheck, rctFlags.cfgEvtRCTFlagCheckerLimitAcceptAsBad); |
| 113 | + |
| 114 | + registry.add("hCentrality", "Centrality; #Events; Centrality (%)", {HistType::kTH1D, {axisCent}}); |
| 115 | + registry.add("hSPplaneA", "Spectator Plane Angle A; #Events; #Psi_{A}", {HistType::kTH1D, {axisPhiPlane}}); |
| 116 | + registry.add("qAqCXY", "Qx ZDCA x Qy ZDCC vs cent ; #ltQ_{X}^{A}Q_{Y}^{C}#GT; Centrality (%)", {HistType::kTH2D, {axisCent, axisQQ}}); |
| 117 | + // Add here the histograms for the spectator plane angle C |
| 118 | + // registry.add(.........) |
| 119 | + registry.add("hSPplaneAvsC", "Spectator Plane Angle A vs C; #Events; #Psi_{A}; #Psi_{C}", {HistType::kTH2D, {axisPhiPlane, axisPhiPlane}}); |
| 120 | + registry.add("hSPplaneFull", "Spectator Plane Angle Full; #Events; #Psi_{Full}", {HistType::kTH1D, {axisPhiPlane}}); |
| 121 | + |
| 122 | + // Note: we will fill these with data from the CCDB, just to take a look! |
| 123 | + registry.add("CalibHistos/hQQx", "QQx; #Events; QQx", {HistType::kTProfile, {axisCent}}); |
| 124 | + registry.add("CalibHistos/hQQy", "QQy; #Events; QQy", {HistType::kTProfile, {axisCent}}); |
| 125 | + registry.add("CalibHistos/hQQ", "QQ; #Events; QQx + QQy", {HistType::kTProfile, {axisCent}}); |
| 126 | + // Add here the histograms for the cross-terms of the Q-vectors from the ZDC |
| 127 | + |
| 128 | + registry.add("CalibHistos/hEvPlaneRes", "Event Plane Resolution; #Events; Event Plane Resolution", {HistType::kTProfile, {axisCent}}); |
| 129 | + |
| 130 | + // Flow Histograms |
| 131 | + registry.add("flow/v1A", "", {HistType::kTProfile, {axisPt}}); |
| 132 | + registry.add("flow/v1C", "", {HistType::kTProfile, {axisPt}}); |
| 133 | + |
| 134 | + registry.add("flow/vnAxCxUxMH", "", {HistType::kTProfile, {axisCent}}); |
| 135 | + registry.add("flow/vnAyCyUxMH", "", {HistType::kTProfile, {axisCent}}); |
| 136 | + registry.add("flow/vnAxCyUyMH", "", {HistType::kTProfile, {axisCent}}); |
| 137 | + registry.add("flow/vnAyCxUyMH", "", {HistType::kTProfile, {axisCent}}); |
| 138 | + } |
| 139 | + |
| 140 | + void process(ZDCCollisions::iterator const& collision, aod::BCsWithTimestamps const&, UsedTracks const& tracks) |
| 141 | + { |
| 142 | + |
| 143 | + auto bc = collision.bc_as<aod::BCsWithTimestamps>(); |
| 144 | + |
| 145 | + float centrality = collision.centFT0C(); |
| 146 | + registry.fill(HIST("hCentrality"), centrality); |
| 147 | + |
| 148 | + float centMin = 0; |
| 149 | + float centMax = 80; |
| 150 | + |
| 151 | + if (centrality > centMax || centrality < centMin) |
| 152 | + return; |
| 153 | + |
| 154 | + if (collision.isSelected() == false) |
| 155 | + return; |
| 156 | + |
| 157 | + // Get the ZDC q-vectors |
| 158 | + double qxA = collision.qxA(); |
| 159 | + double qyA = collision.qyA(); |
| 160 | + double qxC = collision.qxC(); |
| 161 | + double qyC = collision.qyC(); |
| 162 | + |
| 163 | + // Calculate the spectator plane angles |
| 164 | + double psiA = 1.0 * std::atan2(qyA, qxA); |
| 165 | + registry.fill(HIST("hSPplaneA"), psiA); |
| 166 | + |
| 167 | + // Add the PsiA vs PsiC as a TH2D |
| 168 | + |
| 169 | + double psiC = 1.0 * std::atan2(qyC, qxC); |
| 170 | + double psiFull = 1.0 * std::atan2(qyA + qyC, qxA + qxC); |
| 171 | + registry.fill(HIST("hSPplaneFull"), psiFull); |
| 172 | + |
| 173 | + registry.fill(HIST("hSPplaneAvsC"), psiA, psiC); |
| 174 | + |
| 175 | + // Fill the q-vector correlations |
| 176 | + registry.fill(HIST("qAqCXY"), centrality, qxA * qxC + qyA * qyC); |
| 177 | + |
| 178 | + double corrQQx = 1; |
| 179 | + double corrQQy = 1; |
| 180 | + double corrQQ = 1; |
| 181 | + double evPlaneRes = 1; |
| 182 | + |
| 183 | + // Get QQ-correlations from CCDB |
| 184 | + if (cfgCCDBdir_QQ.value.empty() == false) { |
| 185 | + TList* list = ccdb->getForTimeStamp<TList>(cfgCCDBdir_QQ.value, bc.timestamp()); |
| 186 | + TProfile* qAqCX = reinterpret_cast<TProfile*>(list->FindObject("qAqCX")); |
| 187 | + TProfile* qAqCY = reinterpret_cast<TProfile*>(list->FindObject("qAqCY")); |
| 188 | + TProfile* qAqCXY = reinterpret_cast<TProfile*>(list->FindObject("qAqCXY")); |
| 189 | + // The sum is qAqCXY |
| 190 | + corrQQx = qAqCX->GetBinContent(centrality); |
| 191 | + corrQQy = qAqCY->GetBinContent(centrality); |
| 192 | + corrQQ = qAqCXY->GetBinContent(centrality); |
| 193 | + registry.fill(HIST("CalibHistos/hQQx"), centrality, corrQQx); |
| 194 | + registry.fill(HIST("CalibHistos/hQQy"), centrality, corrQQy); |
| 195 | + registry.fill(HIST("CalibHistos/hQQ"), centrality, corrQQ); |
| 196 | + } |
| 197 | + // Get event plane resolution from CCDB |
| 198 | + if (cfgCCDBdir_SP.value.empty() == false) { |
| 199 | + evPlaneRes = ccdb->getForTimeStamp<TProfile>(cfgCCDBdir_SP.value, bc.timestamp())->GetBinContent(centrality); |
| 200 | + registry.fill(HIST("CalibHistos/hEvPlaneRes"), centrality, evPlaneRes); |
| 201 | + } |
| 202 | + |
| 203 | + for (const auto& track : tracks) { |
| 204 | + |
| 205 | + // constrain angle to 0 -> [0,0+2pi] |
| 206 | + auto phi = RecoDecay::constrainAngle(track.phi(), 0); |
| 207 | + |
| 208 | + double ux = std::cos(phi); |
| 209 | + double uy = std::sin(phi); |
| 210 | + |
| 211 | + double uxMH = std::cos(2 * phi); |
| 212 | + double uyMH = std::sin(2 * phi); |
| 213 | + |
| 214 | + double v1A = (uy * qyA + ux * qxA) / std::sqrt(std::fabs(corrQQ)); |
| 215 | + double v1C = (uy * qyC + ux * qxC) / std::sqrt(std::fabs(corrQQ)); |
| 216 | + |
| 217 | + double v2AxCxUxMH = (uxMH * qxA * qxC) / corrQQx; |
| 218 | + double v2AyCyUxMH = (uxMH * qyA * qyC) / corrQQy; |
| 219 | + double v2AxCyUyMH = (uyMH * qxA * qyC) / corrQQx; |
| 220 | + double v2AyCxUyMH = (uyMH * qyA * qxC) / corrQQy; |
| 221 | + |
| 222 | + registry.fill(HIST("flow/v1A"), track.eta(), v1A); |
| 223 | + registry.fill(HIST("flow/v1C"), track.eta(), v1C); |
| 224 | + |
| 225 | + registry.fill(HIST("flow/v2AxCxUxMH"), centrality, v2AxCxUxMH); |
| 226 | + registry.fill(HIST("flow/v2AyCyUxMH"), centrality, v2AyCyUxMH); |
| 227 | + registry.fill(HIST("flow/v2AxCyUyMH"), centrality, v2AxCyUyMH); |
| 228 | + registry.fill(HIST("flow/v2AyCxUyMH"), centrality, v2AyCxUyMH); |
| 229 | + } |
| 230 | + } |
| 231 | +}; |
| 232 | + |
| 233 | +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) |
| 234 | +{ |
| 235 | + return WorkflowSpec{ |
| 236 | + adaptAnalysisTask<SpectatorPlaneTutorial>(cfgc)}; |
| 237 | +} |
0 commit comments