From c48907280b2d877d619c9c27ffbbf308a0d66d5c Mon Sep 17 00:00:00 2001 From: Pengchong Hu Date: Tue, 21 Apr 2026 14:33:50 +0200 Subject: [PATCH 01/11] adding new analysis task for multiharmonic correlations --- .../Tasks/CMakeLists.txt | 5 + .../Tasks/multiharmonic-correlations.cxx | 600 ++++++++++++++++++ 2 files changed, 605 insertions(+) create mode 100644 PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx diff --git a/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt b/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt index 05bb4edb850..7ca923a7e92 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt +++ b/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt @@ -23,3 +23,8 @@ o2physics_add_dpl_workflow(three-particle-correlations SOURCES threeParticleCorrelations.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) + +o2physics_add_dpl_workflow(multiharmonic-correlations + SOURCES multiharmonic-correlations.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore + COMPONENT_NAME Analysis) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx new file mode 100644 index 00000000000..e6cff2e14f0 --- /dev/null +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx @@ -0,0 +1,600 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// student-o2physics.cxx +/// \brief +/// Hu,Pengchong + +// O2: +#include "Common/DataModel/Centrality.h" +#include "Common/DataModel/EventSelection.h" +#include "Common/DataModel/Multiplicity.h" +#include "Common/DataModel/TrackSelectionTables.h" // needed for aod::TracksDCA table + +#include "Framework/AnalysisDataModel.h" +#include "Framework/AnalysisTask.h" +#include "Framework/DataTypes.h" +#include "Framework/runDataProcessing.h" +#include +// ... + +using namespace o2; +using namespace o2::framework; +// ... + +// Definitions of join tables for Run 3 analysis: +using EventSelection = soa::Join; +using CollisionRec = soa::Join::iterator; // use in json "isMC": "true" for "event-selection-task" +using CollisionRecSim = soa::Join::iterator; +using CollisionSim = aod::McCollision; +using TracksRec = soa::Join; +using TrackRec = soa::Join::iterator; +using TracksRecSim = soa::Join; // + use in json "isMC" : "true" +using TrackRecSim = soa::Join::iterator; +using TracksSim = aod::McParticles; +using TrackSim = aod::McParticles::iterator; +// ... + +// *) ROOT and C++ include's: +#include +#include +#include +#include +#include +// ... + +using namespace std; +// ... + +// *) Define enums: +enum eRecSim { eRec = 0, + eSim, + eRecAndSim }; + +enum eProcess { + eProcessRec = 0, // Run 3, only reconstructed + eProcessRecSim, // Run 3, both reconstructed and simulated + eProcessSim, // Run 3, only simulated + eProcess_N +}; + + +enum eEventHistograms { + eVertexZ = 0, + ePt, + eEventHistograms_N +}; + +// *) Main task: +struct MultiharmonicCorrelations { // this name is used in lower-case format to name the TDirectoryFile in AnalysisResults.root + Service ccdb; + + // *) Base TList to hold all output objects: + TString sBaseListName = "Default list name"; + OutputObj fBaseList{sBaseListName.Data(), + OutputObjHandlingPolicy::AnalysisObject, + OutputObjSourceType::OutputObjSource}; + + // *) Define configurables: + Configurable cfDryRun{"cfDryRun", false, "book all histos and run without filling and calculating anything"}; // example for built-in type (float, string, etc.) + Configurable> cf_pt_bins{"cf_pt_bins", {1000, 0., 100.}, "nPtBins, ptMin, ptMax"}; // example for an array + Configurable> cf_phi_bins{"cf_phi_bins", {100, 0., o2::constants::math::TwoPI}, "nPhiBins, phiMin, phiMax"}; + Configurable> cf_centr_bins{"cf_centr_bins", {1000, 0., 100.}, "nCentrBins, centrMin, centrMax"}; + Configurable> cf_x_bins{"cf_x_bins", {1000, -100., 100.}, "nXBins, xMin, xMax"}; + Configurable> cf_y_bins{"cf_y_bins", {1000, -100., 100.}, "nYBins, yMin, yMax"}; + Configurable> cf_z_bins{"cf_z_bins", {1000, -100., 100.}, "nZBins, zMin, zMax"}; + Configurable> cf_mult_bins{"cf_mult_bins", {50, 0, 3e3}, "nMultBins, multMin, multMax"}; + + Configurable cfCent{"cfCent", 1, "centrality estimator"}; + Configurable cfMult{"cfMult", 1, "multiplicity"}; + Configurable cfQA{"cfQA", true, "quality assurance"}; + + Configurable> cfVertexZ{"cfVertexZ", {-10, 10.}, "vertex z position range: {min, max}[cm], with convention: min <= Vz < max"}; + Configurable> cfPt{"cfPt", {0.2, 5.0}, "transverse momentum range"}; + + Configurable cfFileWithWeights{"cfFileWithWeights", "~/O2/weights.root", "path to external ROOT file which holds all particle weights"}; + + // *) Define and initialize all data members to be called in the main process* functions: + // **) Task configuration: + struct TaskConfiguration { + bool fProcess[eProcess_N] = {false}; // Set what to process. See enum eProcess for full description. Set via implicit variables within a PROCESS_SWITCH clause. + bool fDryRun = false; // book all histos and run without filling and calculating anything + } tc; // you have to prepend "tc." for all objects name in this group later in the code + + // **) Particle histograms: + struct ParticleHistograms { + TList* fParticleHistogramsList = NULL; //!Get("hist-name"). + + // Usage: TH1D *hist = (TH1D*) GetObjectFromList("some-valid-TList-pointer","some-object-name"); + + // Insanity checks: + if (!list) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + if (!objectName) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + if (0 == list->GetEntries()) { + return NULL; + } + + // The object is in the current base list: + TObject* objectFinal = list->FindObject(objectName); // the final object I am after + if (objectFinal ) { return objectFinal; } + + //Otherwise, search for the object recursively in the nested lists: + TObject* objectIter; // iterator object in the loop below + TIter next(list); + while ((objectIter = next())) // double round braces are to silence the warnings + { + if (TString(objectIter->ClassName()).EqualTo("TList")) { + objectFinal = GetObjectFromList(reinterpret_cast(objectIter), objectName); + if (objectFinal) + return objectFinal; + } + } // while(objectIter = next()) + + return NULL; + + } // TObject* GetObjectFromList(TList *list, char *objectName) + + + TH1F* GetHistogramWithWeights(const char* filePath, const char* runNumber) + { + // *) Return value: + TH1F* hist = NULL; + TList* baseList = NULL; // base top-level list in the TFile, e.g. named "ccdb_object" + TList* listWithRuns = NULL; // nested list with run-wise TList's holding run-specific weights + + // *) Determine from filePath if the file is on a local machine, or in home dir AliEn, or in CCDB: + // Algorithm: If filePath begins with "/alice/cern.ch/" then it's in the home dir AliEn; + // If filePath begins with "/alice-ccdb.cern.ch/" then it's in CCDB. Therefore, files in AliEn and CCDB must be specified with abs path; + // for local files both abs and relative paths are just fine. + bool bFileIsInAliEn = false; + bool bFileIsInCCDB = false; + + string pathstr=filePath; + const string pathalien="/alice/cern.ch/"; + const string pathccdb="/alice-ccdb.cern.ch/"; + if(pathstr.find(pathalien)==0){ + bFileIsInAliEn=true; + } + else if(pathstr.find(pathccdb)==0){ + bFileIsInCCDB=true; + } + + if (bFileIsInAliEn) { + TGrid* alien = TGrid::Connect("alien", gSystem->Getenv("USER"), "", ""); // do not forget to add #include to the preamble of your analysis task + if (!alien) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + TFile* weightsFile = TFile::Open(Form("alien://%s", filePath), "READ"); // yes, ROOT can open a file transparently, even if it's sitting in AliEn, with this specific syntax + if (!weightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + weightsFile->GetObject("ccdb_object", baseList); + if (!baseList) { + // weightsFile->ls(); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + // Finally, from the top-level TList, get the desired nested TList => the technical problem here is that it can be nested at any level, + // for thare there is a helper utility function GetObjectFromList(...) , see its implementation further below + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } + + } else if (bFileIsInCCDB) { + // File you want to access is in your home dir in CCDB: + // Remember that here I do not access the file; instead, I directly access the object in that file. + ccdb->setURL("http://alice-ccdb.cern.ch"); // to be able to use "ccdb" this object in your analysis task, see 4b/ below + baseList = reinterpret_cast(ccdb->get(TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data())); + if (!baseList) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + } + + // OK, we got the desired TList with efficiency corrections, after that we can use the common code for all 3 cases (local, AliEn, CCDB, that common code is below) + + } else{ + // this is the local case: + // Check if the external ROOT file exists at the specified path: + if (gSystem->AccessPathName(filePath, kFileExists)) { + LOGF(info, "\033[1;33m if(gSystem->AccessPathName(filePath,kFileExists)), filePath = %s \033[0m", filePath); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + TFile* weightsFile = TFile::Open(filePath, "READ"); + if (!weightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + weightsFile->GetObject("ccdb_object", baseList); + + if (!baseList) { + // weightsFile->ls(); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); + if (!listWithRuns) { + TString runNumberWithLeadingZeroes = "000"; + runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); + if (!listWithRuns) { + // baseList->ls(); + LOGF(fatal, "\033[1;31m%s at line %d : this crash can happen if in the output file there is no list with weights for the current run number = %s\033[0m", __FUNCTION__, __LINE__ /*, tc.fRunNumber.Data()*/ ); + } + } + + } // end of else + + // Here comes the common code for all three cases, where from "listWithRuns" you fetch the desired histogram with efficiency corrections: + listWithRuns->ls(); + + hist= (TH1F*) listWithRuns->FindObject("histWithEfficiencyCorrections"); + if(!hist){ + LOGF(fatal, "no histweight"); + } + + // Once you have a valid pointer to "hist", add these technical lines: + hist->SetDirectory(0); // remove ownerhip from an external file + TH1F* histClone = reinterpret_cast(hist->Clone()); // yes, I have to clone here + delete baseList; // release back the memory + + return histClone; + +} // end of TH1F* GetHistogramWithWeights(const char* filePath, const char* runNumber) { + + // ... + + // *) Define all member functions to be called in the main process* functions: + template + bool EventCuts(T1 const& collision) + { + vector vertexZ = cfVertexZ.value; + float vertexZmin = (float)vertexZ[0]; + float vertexZmax = (float)vertexZ[1]; + float posZ = collision.posZ(); + if (posZ < vertexZmin || posZ > vertexZmax) + return false; + return true; + } + + template + bool ParticleCuts(T const& track) + { + vector Pt = cfPt.value; + float ptcutmin = (float)Pt[0]; + float ptcutmax = (float)Pt[1]; + float pt = track.pt(); + if (pt < ptcutmin || pt > ptcutmax) + return false; + return true; + } + + template + void Steer(T1 const& collision, T2 const& tracks) + { + // Dry run: + if (tc.fDryRun) { + return; + } + // Print current run number: + LOGF(info, "Run number: %d", collision.bc().runNumber()); + // Print centrality estimated with "FT0M" estimator: + LOGF(info, "Centrality: %f", collision.centFT0M()); + // Print vertex X position: + LOGF(info, "Vertex X position: %f", collision.posX()); + + float zrec = 0., zsim = 0.; + if constexpr (rs == eRec || rs == eRecAndSim) { + event.fHistX[eRec]->Fill(collision.posX()); + event.fHistY[eRec]->Fill(collision.posY()); + event.fHistZ[eRec]->Fill(collision.posZ()); + event.fEventHistograms[eVertexZ][eRec][0]->Fill(collision.posZ()); + zrec = collision.posZ(); + float centr = 0; + if (cfCent == 1) + centr = collision.centFT0C(); + if (cfCent == 2) + centr = collision.centFT0M(); + if (cfCent == 3) + centr = collision.centFT0A(); + event.fHistCentr[eRec]->Fill(centr); + if (cfMult == 1) + event.fHistMult[eRec]->Fill(collision.multTPC()); + if (cfMult == 2) + event.fHistMult[eRec]->Fill(collision.multFV0M()); + if (cfMult == 3) + event.fHistMult[eRec]->Fill(collision.multFT0C()); + if (cfMult == 4) + event.fHistMult[eRec]->Fill(collision.multFT0M()); + if (cfMult == 5) + event.fHistMult[eRec]->Fill(collision.multNTracksPV()); + + if constexpr (rs == eRecAndSim) { + auto mccollision = collision.mcCollision(); + float b = mccollision.impactParameter(); + float centrsim = o2::constants::math::PI * b * b / 7.71; + event.fHistX[eSim]->Fill(mccollision.posX()); + event.fHistY[eSim]->Fill(mccollision.posY()); + event.fHistZ[eSim]->Fill(mccollision.posZ()); + event.fEventHistograms[eVertexZ][eSim][0]->Fill(mccollision.posZ()); + zsim = mccollision.posZ(); + event.fHistCentr[eSim]->Fill(centrsim); + event.fQA->Fill(centrsim, centr); + // event.fHistMult[eSim]->Fill(tracks.size()); + } + + // *) Event cuts: + if (!EventCuts(collision)) { // Main call for event cuts + return; + } + event.fEventHistograms[eVertexZ][eRec][1]->Fill(zrec); + if constexpr (rs == eRecAndSim) + event.fEventHistograms[eVertexZ][eSim][1]->Fill(zsim); + } + + // Main loop over particles: + auto track = tracks.iteratorAt(0); // set the type and scope from one instance + for (int64_t i = 0; i < tracks.size(); i++) { + + // Print track azimuthal angle: + // LOGF(info, "Track azimuthal angle: %f", track.phi()); + //pc.histWeights=GetHistogramWithWeights(cfFileWithWeights.value.c_str(), "000123456"); + + // Fill reconstructed ...: + float ptrec = 0., ptsim = 0.; + if constexpr (rs == eRec || rs == eRecAndSim) { + // Fill track pt distribution: + pc.fHistPt[eRec]->Fill(track.pt()); + event.fEventHistograms[ePt][eRec][0]->Fill(track.pt()); + ptrec = track.pt(); + pc.fHistPhi[eRec]->Fill(track.phi()); + + // ... and corresponding MC truth simulated: + // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx + // See https://aliceo2group.github.io/analysis-framework/docs/datamodel/ao2dTables.html#montecarlo + if constexpr (rs == eRecAndSim) { + if (!track.has_mcParticle()) { + LOGF(warning, " No MC particle for this track, skip..."); + return; + } + auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle + auto mccollision = collision.mcCollision(); + pc.fHistPt[eSim]->Fill(mcparticle.pt()); + event.fEventHistograms[ePt][eSim][0]->Fill(mcparticle.pt()); + ptsim = mcparticle.pt(); + pc.fHistPhi[eSim]->Fill(mcparticle.phi()); + } // end of if constexpr (rs == eRecAndSim) { + + // *) Particle cuts: + if (!ParticleCuts(track)) { // Main call for particle cuts. + continue; // not return!! + } + event.fEventHistograms[ePt][eRec][1]->Fill(ptrec); + if constexpr (rs == eRecAndSim) + event.fEventHistograms[ePt][eSim][0]->Fill(ptsim); + + } // if constexpr (rs == eRec || rs == eRecAndSim) { + } // end of for (int64_t i = 0; i < tracks.size(); i++) { + + } // end of template void Steer(T1 const& collision, T2 const& tracks) { + + // *) Initialize and book all objects: + void init(InitContext&) + { + + // ... code to book and initialize all analysis objects ... + + // *) Set automatically what to process, from an implicit variable "doprocessSomeProcessName" within a PROCESS_SWITCH clause: + tc.fProcess[eProcessRec] = doprocessRec; + tc.fProcess[eProcessRecSim] = doprocessRecSim; + tc.fProcess[eProcessSim] = doprocessSim; + + // *) Configure your task using configurables in the json file: + tc.fDryRun = cfDryRun; + + // *) Book base list: + TList* temp = new TList(); + temp->SetOwner(true); + fBaseList.setObject(temp); + + // *) Book and nest all other TLists: + pc.fParticleHistogramsList = new TList(); + pc.fParticleHistogramsList->SetName("ParticleHistograms"); + pc.fParticleHistogramsList->SetOwner(true); + fBaseList->Add(pc.fParticleHistogramsList); // any nested TList in the base TList appears as a subdir in the output ROOT file + event.fEventHistogramsList = new TList(); + event.fEventHistogramsList->SetName("EventHistograms"); + event.fEventHistogramsList->SetOwner(true); + fBaseList->Add(event.fEventHistogramsList); + + // *) Book pt distribution with binning defined through configurables in the json file: + vector l_pt_bins = cf_pt_bins.value; // define local array and initialize it from an array set in the configurables + vector l_phi_bins = cf_phi_bins.value; + vector l_centr_bins = cf_centr_bins.value; + vector l_x_bins = cf_x_bins.value; + vector l_y_bins = cf_y_bins.value; + vector l_z_bins = cf_z_bins.value; + vector l_mult_bins = cf_mult_bins.value; + int nBins = (Int_t)l_pt_bins[0]; + int nBinsphi = (Int_t)l_phi_bins[0]; + int nBinscentr = (Int_t)l_centr_bins[0]; + int nBinsx = (Int_t)l_x_bins[0]; + int nBinsy = (Int_t)l_y_bins[0]; + int nBinsz = (Int_t)l_z_bins[0]; + int nBinsmult = (Int_t)l_mult_bins[0]; + + float min = l_pt_bins[1]; + float max = l_pt_bins[2]; + float minphi = l_phi_bins[1]; + float maxphi = l_phi_bins[2]; + float mincentr = l_centr_bins[1]; + float maxcentr = l_centr_bins[2]; + float minx = l_x_bins[1]; + float maxx = l_x_bins[2]; + float miny = l_y_bins[1]; + float maxy = l_y_bins[2]; + float minz = l_z_bins[1]; + float maxz = l_z_bins[2]; + float minmult = l_mult_bins[1]; + float maxmult = l_mult_bins[2]; + + pc.fHistPt[eRec] = new TH1F("fHistPt[eRec]", "pt distribution for reconstructed particles", nBins, min, max); + pc.fHistPt[eRec]->GetXaxis()->SetTitle("p_{T}"); + pc.fParticleHistogramsList->Add(pc.fHistPt[eRec]); + pc.fHistPhi[eRec] = new TH1F("fHistPhi[eRec]", "phi distribution for reconstructed particles", nBinsphi, minphi, maxphi); + pc.fHistPhi[eRec]->GetXaxis()->SetTitle("phi"); + pc.fParticleHistogramsList->Add(pc.fHistPhi[eRec]); + + pc.fHistPt[eSim] = new TH1F("fHistPt[eSim]", "pt distribution for simulated particles", nBins, min, max); + pc.fHistPt[eSim]->GetXaxis()->SetTitle("p_{T}"); + pc.fParticleHistogramsList->Add(pc.fHistPt[eSim]); + pc.fHistPhi[eSim] = new TH1F("fHistPhi[eSim]", "phi distribution for simulated particles", nBinsphi, minphi, maxphi); + pc.fHistPhi[eSim]->GetXaxis()->SetTitle("phi"); + pc.fParticleHistogramsList->Add(pc.fHistPhi[eSim]); + + pc.histWeights=GetHistogramWithWeights(cfFileWithWeights.value.c_str(), "000123456"); + pc.fParticleHistogramsList->Add(pc.histWeights); + + event.fHistCentr[eRec] = new TH1F("fHistCentr[eRec]", "centrality distribution for reconstructed particles", nBinscentr, mincentr, maxcentr); + event.fHistX[eRec] = new TH1F("fHistX[eRec]", "posX distribution for reconstructed particles", nBinsx, minx, maxx); + event.fHistY[eRec] = new TH1F("fHistY[eRec]", "posY distribution for reconstructed particles", nBinsy, miny, maxy); + event.fHistZ[eRec] = new TH1F("fHistZ[eRec]", "posZ distribution for reconstructed particles", nBinsz, minz, maxz); + event.fHistMult[eRec] = new TH1I("fHistMult[eRec]", "mult distribution for reconstructed particles", nBinsmult, minmult, maxmult); + event.fHistCentr[eRec]->GetXaxis()->SetTitle("centrality"); + event.fHistX[eRec]->GetXaxis()->SetTitle("x"); + event.fHistY[eRec]->GetXaxis()->SetTitle("y"); + event.fHistZ[eRec]->GetXaxis()->SetTitle("z"); + event.fHistMult[eRec]->GetXaxis()->SetTitle("multiplicity"); + event.fEventHistogramsList->Add(event.fHistCentr[eRec]); + event.fEventHistogramsList->Add(event.fHistX[eRec]); + event.fEventHistogramsList->Add(event.fHistY[eRec]); + event.fEventHistogramsList->Add(event.fHistZ[eRec]); + event.fEventHistogramsList->Add(event.fHistMult[eRec]); + + event.fHistCentr[eSim] = new TH1F("fHistCentr[eSim]", "centrality distribution for simulated particles", nBinscentr, mincentr, maxcentr); + event.fHistX[eSim] = new TH1F("fHistX[eSim]", "posX distribution for simulated particles", nBinsx, minx, maxx); + event.fHistY[eSim] = new TH1F("fHistY[eSim]", "posY distribution for simulated particles", nBinsy, miny, maxy); + event.fHistZ[eSim] = new TH1F("fHistZ[eSim]", "posZ distribution for simulated particles", nBinsz, minz, maxz); + event.fHistMult[eSim] = new TH1I("fHistMult[eSim]", "mult distribution for simulated particles", nBinsmult, minmult, maxmult); + event.fHistCentr[eSim]->GetXaxis()->SetTitle("centrality"); + event.fHistX[eSim]->GetXaxis()->SetTitle("x"); + event.fHistY[eSim]->GetXaxis()->SetTitle("y"); + event.fHistZ[eSim]->GetXaxis()->SetTitle("z"); + event.fHistMult[eSim]->GetXaxis()->SetTitle("multiplicity"); + event.fEventHistogramsList->Add(event.fHistCentr[eSim]); + event.fEventHistogramsList->Add(event.fHistX[eSim]); + event.fEventHistogramsList->Add(event.fHistY[eSim]); + event.fEventHistogramsList->Add(event.fHistZ[eSim]); + event.fEventHistogramsList->Add(event.fHistMult[eSim]); + + const char* cevent[] = {"vertexZ", "Pt"}; + const char* cpro[] = {"rec", "sim"}; + const char* ccut[] = {"before", "after"}; + for (int i = 0; i < eEventHistograms_N; i++) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { + TString histname = Form("fEventHistograms[%s][%s][%s]", cevent[i], cpro[j], ccut[k]); + TString histtitle = Form("%s distribution for %s, %s cut", cevent[i], cpro[j], ccut[k]); + if (i == 0) + event.fEventHistograms[i][j][k] = new TH1F(histname, histtitle, nBinsz, minz, maxz); + if (i == 1) + event.fEventHistograms[i][j][k] = new TH1F(histname, histtitle, nBins, min, max); + event.fEventHistograms[i][j][k]->GetXaxis()->SetTitle(Form("%s", cevent[i])); + event.fEventHistogramsList->Add(event.fEventHistograms[i][j][k]); + } + } + } + + event.fQA = new TH2F("QA", "quality assurance", nBinscentr, mincentr, maxcentr, nBinscentr, mincentr, maxcentr); + if (cfQA) { + event.fEventHistogramsList->Add(event.fQA); + } + + } // end of void init(InitContext&) { + + // A) Process only reconstructed data: + void processRec(CollisionRec const& collision, aod::BCs const&, TracksRec const& tracks) + { + // ... + + // *) Steer all analysis steps: + Steer(collision, tracks); + } + PROCESS_SWITCH(MultiharmonicCorrelations, processRec, "process only reconstructed data", true); // yes, keep always one process switch "true", so that there is default running version + + // ------------------------------------------- + + // B) Process both reconstructed and corresponding MC truth simulated data: + void processRecSim(CollisionRecSim const& collision, aod::BCs const&, TracksRecSim const& tracks, aod::McParticles const&, aod::McCollisions const&) + { + Steer(collision, tracks); + } + PROCESS_SWITCH(MultiharmonicCorrelations, processRecSim, "process both reconstructed and corresponding MC truth simulated data", false); + + // ------------------------------------------- + + // C) Process only simulated data: + void processSim(CollisionSim const& /*collision*/, aod::BCs const&, TracksSim const& /*tracks*/) + { + // Steer(collision, tracks); // TBI 20241105 not ready yet, but I do not really need this one urgently, since RecSim is working, and I need that one for efficiencies... + } + PROCESS_SWITCH(MultiharmonicCorrelations, processSim, "process only simulated data", false); + +}; // struct MultiharmonicCorrelations { + +// *) The final touch: +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} // WorkflowSpec... From 6feabf61707ebd7120365b00eafe018f5e4c94aa Mon Sep 17 00:00:00 2001 From: Pengchong Hu Date: Tue, 21 Apr 2026 14:47:45 +0200 Subject: [PATCH 02/11] fix for format --- .../Tasks/multiharmonic-correlations.cxx | 166 +++++++++--------- 1 file changed, 83 insertions(+), 83 deletions(-) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx index e6cff2e14f0..8a97e92b194 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx @@ -43,11 +43,12 @@ using TrackSim = aod::McParticles::iterator; // ... // *) ROOT and C++ include's: -#include -#include -#include #include +#include #include + +#include +#include // ... using namespace std; @@ -65,7 +66,6 @@ enum eProcess { eProcess_N }; - enum eEventHistograms { eVertexZ = 0, ePt, @@ -106,14 +106,14 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to struct TaskConfiguration { bool fProcess[eProcess_N] = {false}; // Set what to process. See enum eProcess for full description. Set via implicit variables within a PROCESS_SWITCH clause. bool fDryRun = false; // book all histos and run without filling and calculating anything - } tc; // you have to prepend "tc." for all objects name in this group later in the code + } tc; // you have to prepend "tc." for all objects name in this group later in the code // **) Particle histograms: struct ParticleHistograms { TList* fParticleHistogramsList = NULL; //!Get("hist-name"). - - // Usage: TH1D *hist = (TH1D*) GetObjectFromList("some-valid-TList-pointer","some-object-name"); + // Get TObject pointer from TList, even if it's in some nested TList. Foreseen + // to be used to fetch histograms or profiles from files directly. + // Some ideas taken from TCollection::ls() + // If you have added histograms directly to files (without TList's), then you can fetch them directly with + // file->Get("hist-name"). - // Insanity checks: - if (!list) { - LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } - if (!objectName) { - LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } - if (0 == list->GetEntries()) { - return NULL; - } + // Usage: TH1D *hist = (TH1D*) GetObjectFromList("some-valid-TList-pointer","some-object-name"); - // The object is in the current base list: - TObject* objectFinal = list->FindObject(objectName); // the final object I am after - if (objectFinal ) { return objectFinal; } + // Insanity checks: + if (!list) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + if (!objectName) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + if (0 == list->GetEntries()) { + return NULL; + } - //Otherwise, search for the object recursively in the nested lists: - TObject* objectIter; // iterator object in the loop below - TIter next(list); - while ((objectIter = next())) // double round braces are to silence the warnings - { - if (TString(objectIter->ClassName()).EqualTo("TList")) { - objectFinal = GetObjectFromList(reinterpret_cast(objectIter), objectName); - if (objectFinal) - return objectFinal; + // The object is in the current base list: + TObject* objectFinal = list->FindObject(objectName); // the final object I am after + if (objectFinal) { + return objectFinal; } - } // while(objectIter = next()) - return NULL; + // Otherwise, search for the object recursively in the nested lists: + TObject* objectIter; // iterator object in the loop below + TIter next(list); + while ((objectIter = next())) // double round braces are to silence the warnings + { + if (TString(objectIter->ClassName()).EqualTo("TList")) { + objectFinal = GetObjectFromList(reinterpret_cast(objectIter), objectName); + if (objectFinal) + return objectFinal; + } + } // while(objectIter = next()) + + return NULL; } // TObject* GetObjectFromList(TList *list, char *objectName) - TH1F* GetHistogramWithWeights(const char* filePath, const char* runNumber) { // *) Return value: @@ -183,14 +184,13 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to bool bFileIsInAliEn = false; bool bFileIsInCCDB = false; - string pathstr=filePath; - const string pathalien="/alice/cern.ch/"; - const string pathccdb="/alice-ccdb.cern.ch/"; - if(pathstr.find(pathalien)==0){ - bFileIsInAliEn=true; - } - else if(pathstr.find(pathccdb)==0){ - bFileIsInCCDB=true; + string pathstr = filePath; + const string pathalien = "/alice/cern.ch/"; + const string pathccdb = "/alice-ccdb.cern.ch/"; + if (pathstr.find(pathalien) == 0) { + bFileIsInAliEn = true; + } else if (pathstr.find(pathccdb) == 0) { + bFileIsInCCDB = true; } if (bFileIsInAliEn) { @@ -220,17 +220,17 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to } } - } else if (bFileIsInCCDB) { - // File you want to access is in your home dir in CCDB: - // Remember that here I do not access the file; instead, I directly access the object in that file. - ccdb->setURL("http://alice-ccdb.cern.ch"); // to be able to use "ccdb" this object in your analysis task, see 4b/ below - baseList = reinterpret_cast(ccdb->get(TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data())); - if (!baseList) { - LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } - - listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); - if (!listWithRuns) { + } else if (bFileIsInCCDB) { + // File you want to access is in your home dir in CCDB: + // Remember that here I do not access the file; instead, I directly access the object in that file. + ccdb->setURL("http://alice-ccdb.cern.ch"); // to be able to use "ccdb" this object in your analysis task, see 4b/ below + baseList = reinterpret_cast(ccdb->get(TString(filePath).ReplaceAll("/alice-ccdb.cern.ch/", "").Data())); + if (!baseList) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } + + listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); + if (!listWithRuns) { TString runNumberWithLeadingZeroes = "000"; runNumberWithLeadingZeroes += runNumber; // another try, with "000" prepended to run number listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); @@ -241,25 +241,25 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to // OK, we got the desired TList with efficiency corrections, after that we can use the common code for all 3 cases (local, AliEn, CCDB, that common code is below) - } else{ - // this is the local case: - // Check if the external ROOT file exists at the specified path: - if (gSystem->AccessPathName(filePath, kFileExists)) { - LOGF(info, "\033[1;33m if(gSystem->AccessPathName(filePath,kFileExists)), filePath = %s \033[0m", filePath); - LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } + } else { + // this is the local case: + // Check if the external ROOT file exists at the specified path: + if (gSystem->AccessPathName(filePath, kFileExists)) { + LOGF(info, "\033[1;33m if(gSystem->AccessPathName(filePath,kFileExists)), filePath = %s \033[0m", filePath); + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } - TFile* weightsFile = TFile::Open(filePath, "READ"); - if (!weightsFile) { - LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } + TFile* weightsFile = TFile::Open(filePath, "READ"); + if (!weightsFile) { + LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); + } - weightsFile->GetObject("ccdb_object", baseList); + weightsFile->GetObject("ccdb_object", baseList); - if (!baseList) { + if (!baseList) { // weightsFile->ls(); LOGF(fatal, "\033[1;31m%s at line %d\033[0m", __FUNCTION__, __LINE__); - } + } listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumber)); if (!listWithRuns) { @@ -268,28 +268,28 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to listWithRuns = reinterpret_cast(GetObjectFromList(baseList, runNumberWithLeadingZeroes.Data())); if (!listWithRuns) { // baseList->ls(); - LOGF(fatal, "\033[1;31m%s at line %d : this crash can happen if in the output file there is no list with weights for the current run number = %s\033[0m", __FUNCTION__, __LINE__ /*, tc.fRunNumber.Data()*/ ); + LOGF(fatal, "\033[1;31m%s at line %d : this crash can happen if in the output file there is no list with weights for the current run number = %s\033[0m", __FUNCTION__, __LINE__ /*, tc.fRunNumber.Data()*/); } } } // end of else // Here comes the common code for all three cases, where from "listWithRuns" you fetch the desired histogram with efficiency corrections: - listWithRuns->ls(); + listWithRuns->ls(); - hist= (TH1F*) listWithRuns->FindObject("histWithEfficiencyCorrections"); - if(!hist){ + hist = (TH1F*)listWithRuns->FindObject("histWithEfficiencyCorrections"); + if (!hist) { LOGF(fatal, "no histweight"); } - // Once you have a valid pointer to "hist", add these technical lines: - hist->SetDirectory(0); // remove ownerhip from an external file - TH1F* histClone = reinterpret_cast(hist->Clone()); // yes, I have to clone here - delete baseList; // release back the memory + // Once you have a valid pointer to "hist", add these technical lines: + hist->SetDirectory(0); // remove ownerhip from an external file + TH1F* histClone = reinterpret_cast(hist->Clone()); // yes, I have to clone here + delete baseList; // release back the memory - return histClone; + return histClone; -} // end of TH1F* GetHistogramWithWeights(const char* filePath, const char* runNumber) { + } // end of TH1F* GetHistogramWithWeights(const char* filePath, const char* runNumber) { // ... @@ -387,7 +387,7 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to // Print track azimuthal angle: // LOGF(info, "Track azimuthal angle: %f", track.phi()); - //pc.histWeights=GetHistogramWithWeights(cfFileWithWeights.value.c_str(), "000123456"); + // pc.histWeights=GetHistogramWithWeights(cfFileWithWeights.value.c_str(), "000123456"); // Fill reconstructed ...: float ptrec = 0., ptsim = 0.; @@ -501,7 +501,7 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to pc.fHistPhi[eSim]->GetXaxis()->SetTitle("phi"); pc.fParticleHistogramsList->Add(pc.fHistPhi[eSim]); - pc.histWeights=GetHistogramWithWeights(cfFileWithWeights.value.c_str(), "000123456"); + pc.histWeights = GetHistogramWithWeights(cfFileWithWeights.value.c_str(), "000123456"); pc.fParticleHistogramsList->Add(pc.histWeights); event.fHistCentr[eRec] = new TH1F("fHistCentr[eRec]", "centrality distribution for reconstructed particles", nBinscentr, mincentr, maxcentr); From 04994d414e1da7e95d0d588dc825dffdf86ab92a Mon Sep 17 00:00:00 2001 From: Pengchong Hu Date: Tue, 21 Apr 2026 15:00:03 +0200 Subject: [PATCH 03/11] fix for megalinter --- .../Tasks/multiharmonic-correlations.cxx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx index 8a97e92b194..93f8cb6aa6b 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx @@ -49,6 +49,8 @@ using TrackSim = aod::McParticles::iterator; #include #include +#include +#include // ... using namespace std; @@ -277,7 +279,7 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to // Here comes the common code for all three cases, where from "listWithRuns" you fetch the desired histogram with efficiency corrections: listWithRuns->ls(); - hist = (TH1F*)listWithRuns->FindObject("histWithEfficiencyCorrections"); + hist = reinterpret_cast(listWithRuns->FindObject("histWithEfficiencyCorrections")); if (!hist) { LOGF(fatal, "no histweight"); } @@ -298,8 +300,8 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to bool EventCuts(T1 const& collision) { vector vertexZ = cfVertexZ.value; - float vertexZmin = (float)vertexZ[0]; - float vertexZmax = (float)vertexZ[1]; + float vertexZmin = static_cast(vertexZ[0]); + float vertexZmax = static_cast(vertexZ[1]); float posZ = collision.posZ(); if (posZ < vertexZmin || posZ > vertexZmax) return false; @@ -310,8 +312,8 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to bool ParticleCuts(T const& track) { vector Pt = cfPt.value; - float ptcutmin = (float)Pt[0]; - float ptcutmax = (float)Pt[1]; + float ptcutmin = static_cast(Pt[0]); + float ptcutmax = static_cast(Pt[1]); float pt = track.pt(); if (pt < ptcutmin || pt > ptcutmax) return false; From cdfc4ed4da3351be333a405c1280cbefe60a46c2 Mon Sep 17 00:00:00 2001 From: Pengchong Hu Date: Wed, 22 Apr 2026 01:16:11 +0200 Subject: [PATCH 04/11] fix for linter --- .../Tasks/CMakeLists.txt | 2 +- ...ions.cxx => multiharmonicCorrelations.cxx} | 32 ++++++++----------- 2 files changed, 15 insertions(+), 19 deletions(-) rename PWGCF/MultiparticleCorrelations/Tasks/{multiharmonic-correlations.cxx => multiharmonicCorrelations.cxx} (95%) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt b/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt index 7ca923a7e92..f831c2b3177 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt +++ b/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt @@ -25,6 +25,6 @@ o2physics_add_dpl_workflow(three-particle-correlations COMPONENT_NAME Analysis) o2physics_add_dpl_workflow(multiharmonic-correlations - SOURCES multiharmonic-correlations.cxx + SOURCES multiharmonicCorrelations.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx similarity index 95% rename from PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx rename to PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx index 93f8cb6aa6b..2d9438df49f 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonic-correlations.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx @@ -48,7 +48,6 @@ using TrackSim = aod::McParticles::iterator; #include #include -#include #include #include // ... @@ -86,13 +85,13 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to // *) Define configurables: Configurable cfDryRun{"cfDryRun", false, "book all histos and run without filling and calculating anything"}; // example for built-in type (float, string, etc.) - Configurable> cf_pt_bins{"cf_pt_bins", {1000, 0., 100.}, "nPtBins, ptMin, ptMax"}; // example for an array - Configurable> cf_phi_bins{"cf_phi_bins", {100, 0., o2::constants::math::TwoPI}, "nPhiBins, phiMin, phiMax"}; - Configurable> cf_centr_bins{"cf_centr_bins", {1000, 0., 100.}, "nCentrBins, centrMin, centrMax"}; - Configurable> cf_x_bins{"cf_x_bins", {1000, -100., 100.}, "nXBins, xMin, xMax"}; - Configurable> cf_y_bins{"cf_y_bins", {1000, -100., 100.}, "nYBins, yMin, yMax"}; - Configurable> cf_z_bins{"cf_z_bins", {1000, -100., 100.}, "nZBins, zMin, zMax"}; - Configurable> cf_mult_bins{"cf_mult_bins", {50, 0, 3e3}, "nMultBins, multMin, multMax"}; + Configurable> cf_pt_bins{"cf_pt_bins", {1000, 0., 100.}, "nPtBins, ptMin, ptMax"}; // example for an array + Configurable> cf_phi_bins{"cf_phi_bins", {100, 0., o2::constants::math::TwoPI}, "nPhiBins, phiMin, phiMax"}; + Configurable> cf_centr_bins{"cf_centr_bins", {1000, 0., 100.}, "nCentrBins, centrMin, centrMax"}; + Configurable> cf_x_bins{"cf_x_bins", {1000, -100., 100.}, "nXBins, xMin, xMax"}; + Configurable> cf_y_bins{"cf_y_bins", {1000, -100., 100.}, "nYBins, yMin, yMax"}; + Configurable> cf_z_bins{"cf_z_bins", {1000, -100., 100.}, "nZBins, zMin, zMax"}; + Configurable> cf_mult_bins{"cf_mult_bins", {50, 0, 3e3}, "nMultBins, multMin, multMax"}; Configurable cfCent{"cfCent", 1, "centrality estimator"}; Configurable cfMult{"cfMult", 1, "multiplicity"}; @@ -287,7 +286,6 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to // Once you have a valid pointer to "hist", add these technical lines: hist->SetDirectory(0); // remove ownerhip from an external file TH1F* histClone = reinterpret_cast(hist->Clone()); // yes, I have to clone here - delete baseList; // release back the memory return histClone; @@ -388,8 +386,6 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to for (int64_t i = 0; i < tracks.size(); i++) { // Print track azimuthal angle: - // LOGF(info, "Track azimuthal angle: %f", track.phi()); - // pc.histWeights=GetHistogramWithWeights(cfFileWithWeights.value.c_str(), "000123456"); // Fill reconstructed ...: float ptrec = 0., ptsim = 0.; @@ -466,13 +462,13 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to vector l_y_bins = cf_y_bins.value; vector l_z_bins = cf_z_bins.value; vector l_mult_bins = cf_mult_bins.value; - int nBins = (Int_t)l_pt_bins[0]; - int nBinsphi = (Int_t)l_phi_bins[0]; - int nBinscentr = (Int_t)l_centr_bins[0]; - int nBinsx = (Int_t)l_x_bins[0]; - int nBinsy = (Int_t)l_y_bins[0]; - int nBinsz = (Int_t)l_z_bins[0]; - int nBinsmult = (Int_t)l_mult_bins[0]; + int nBins = (int)l_pt_bins[0]; + int nBinsphi = (int)l_phi_bins[0]; + int nBinscentr = (int)l_centr_bins[0]; + int nBinsx = (int)l_x_bins[0]; + int nBinsy = (int)l_y_bins[0]; + int nBinsz = (int)l_z_bins[0]; + int nBinsmult = (int)l_mult_bins[0]; float min = l_pt_bins[1]; float max = l_pt_bins[2]; From 26d1cbe30995d676bc445f006ed65f31eefaafc0 Mon Sep 17 00:00:00 2001 From: Pengchong Hu Date: Wed, 22 Apr 2026 01:32:55 +0200 Subject: [PATCH 05/11] fix for megalinter 2 --- .../Tasks/multiharmonicCorrelations.cxx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx index 2d9438df49f..cc7b81c71d6 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx @@ -462,13 +462,13 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to vector l_y_bins = cf_y_bins.value; vector l_z_bins = cf_z_bins.value; vector l_mult_bins = cf_mult_bins.value; - int nBins = (int)l_pt_bins[0]; - int nBinsphi = (int)l_phi_bins[0]; - int nBinscentr = (int)l_centr_bins[0]; - int nBinsx = (int)l_x_bins[0]; - int nBinsy = (int)l_y_bins[0]; - int nBinsz = (int)l_z_bins[0]; - int nBinsmult = (int)l_mult_bins[0]; + int nBins = static_cast(l_pt_bins[0]); + int nBinsphi = static_cast(l_phi_bins[0]); + int nBinscentr = static_cast(l_centr_bins[0]); + int nBinsx = static_cast(l_x_bins[0]); + int nBinsy = static_cast(l_y_bins[0]); + int nBinsz = static_cast(l_z_bins[0]); + int nBinsmult = static_cast(l_mult_bins[0]); float min = l_pt_bins[1]; float max = l_pt_bins[2]; From 01a4f68dbd9d8e1e14bc96081f1e79e00cd065cd Mon Sep 17 00:00:00 2001 From: Pengchong Hu Date: Wed, 22 Apr 2026 11:55:43 +0200 Subject: [PATCH 06/11] fix for linter 2 --- .../Tasks/multiharmonicCorrelations.cxx | 34 +++++++------------ 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx index cc7b81c71d6..2857a7b0efa 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx @@ -8,26 +8,28 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// student-o2physics.cxx -/// \brief -/// Hu,Pengchong -// O2: #include "Common/DataModel/Centrality.h" #include "Common/DataModel/EventSelection.h" #include "Common/DataModel/Multiplicity.h" #include "Common/DataModel/TrackSelectionTables.h" // needed for aod::TracksDCA table -#include "Framework/AnalysisDataModel.h" -#include "Framework/AnalysisTask.h" -#include "Framework/DataTypes.h" -#include "Framework/runDataProcessing.h" #include -// ... +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include using namespace o2; using namespace o2::framework; -// ... // Definitions of join tables for Run 3 analysis: using EventSelection = soa::Join; @@ -40,20 +42,8 @@ using TracksRecSim = soa::Join::iterator; using TracksSim = aod::McParticles; using TrackSim = aod::McParticles::iterator; -// ... - -// *) ROOT and C++ include's: -#include -#include -#include - -#include -#include -#include -// ... using namespace std; -// ... // *) Define enums: enum eRecSim { eRec = 0, From 93b52d8772e87bdf8eb7bdf13bf0e3a48ae0950c Mon Sep 17 00:00:00 2001 From: Pengchong Hu Date: Thu, 23 Apr 2026 12:36:37 +0200 Subject: [PATCH 07/11] fix for build mac --- .../Tasks/multiharmonicCorrelations.cxx | 1 - 1 file changed, 1 deletion(-) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx index 2857a7b0efa..f47b8e0c4f5 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx @@ -395,7 +395,6 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to return; } auto mcparticle = track.mcParticle(); // corresponding MC truth simulated particle - auto mccollision = collision.mcCollision(); pc.fHistPt[eSim]->Fill(mcparticle.pt()); event.fEventHistograms[ePt][eSim][0]->Fill(mcparticle.pt()); ptsim = mcparticle.pt(); From fb3e94cf1176f17e0ef923e20450f3148807bddf Mon Sep 17 00:00:00 2001 From: Pengchong Hu Date: Tue, 26 May 2026 22:14:44 +0200 Subject: [PATCH 08/11] multiharmoniccorrelations --- .../Tasks/multiharmonicCorrelations.cxx | 237 +++++++++++++++--- 1 file changed, 198 insertions(+), 39 deletions(-) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx index f47b8e0c4f5..3aba74e9d35 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -77,20 +78,25 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to Configurable cfDryRun{"cfDryRun", false, "book all histos and run without filling and calculating anything"}; // example for built-in type (float, string, etc.) Configurable> cf_pt_bins{"cf_pt_bins", {1000, 0., 100.}, "nPtBins, ptMin, ptMax"}; // example for an array Configurable> cf_phi_bins{"cf_phi_bins", {100, 0., o2::constants::math::TwoPI}, "nPhiBins, phiMin, phiMax"}; - Configurable> cf_centr_bins{"cf_centr_bins", {1000, 0., 100.}, "nCentrBins, centrMin, centrMax"}; + Configurable> cf_centr_bins{"cf_centr_bins", {100, 0., 100.}, "nCentrBins, centrMin, centrMax"}; Configurable> cf_x_bins{"cf_x_bins", {1000, -100., 100.}, "nXBins, xMin, xMax"}; Configurable> cf_y_bins{"cf_y_bins", {1000, -100., 100.}, "nYBins, yMin, yMax"}; Configurable> cf_z_bins{"cf_z_bins", {1000, -100., 100.}, "nZBins, zMin, zMax"}; Configurable> cf_mult_bins{"cf_mult_bins", {50, 0, 3e3}, "nMultBins, multMin, multMax"}; + Configurable> cf_tpcncls_bins{"cf_tpcncls_bins", {100, 0., 1000.}, "ntpcnclsBins, tpnclsMin, tpcnclsMax"}; + Configurable> cf_dcaxy_bins{"cf_dcaxy_bins", {1000, -20., 20.}, "ndcaxyBins, dcaxyMin, dcaxyMax"}; + Configurable> cf_dcaz_bins{"cf_dcaz_bins", {1000, -10., 10.}, "ndcazBins, dcazMin, dcazMax"}; + Configurable> cf_ncontr_bins{"cf_ncontr_bins", {100, 0., 1000}, "nNContrBins, NContrMin, NContrMax"}; Configurable cfCent{"cfCent", 1, "centrality estimator"}; - Configurable cfMult{"cfMult", 1, "multiplicity"}; + Configurable cfMult{"cfMult", "TPC", "multiplicity"}; Configurable cfQA{"cfQA", true, "quality assurance"}; Configurable> cfVertexZ{"cfVertexZ", {-10, 10.}, "vertex z position range: {min, max}[cm], with convention: min <= Vz < max"}; Configurable> cfPt{"cfPt", {0.2, 5.0}, "transverse momentum range"}; + Configurable> cfEta{"cfEta", {-0.8, 0.8}, "eta range"}; - Configurable cfFileWithWeights{"cfFileWithWeights", "~/O2/weights.root", "path to external ROOT file which holds all particle weights"}; + Configurable cfFileWithWeights{"cfFileWithWeights", "/alice-ccdb.cern.ch/Users/p/pengchon/test04", "path to external ROOT file which holds all particle weights"}; // *) Define and initialize all data members to be called in the main process* functions: // **) Task configuration: @@ -104,6 +110,10 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to TList* fParticleHistogramsList = NULL; //!Getenv("USER"), "", ""); // do not forget to add #include to the preamble of your analysis task @@ -291,7 +318,7 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to float vertexZmin = static_cast(vertexZ[0]); float vertexZmax = static_cast(vertexZ[1]); float posZ = collision.posZ(); - if (posZ < vertexZmin || posZ > vertexZmax) + if (posZ < vertexZmin || posZ > vertexZmax || (!collision.sel8())) return false; return true; } @@ -303,11 +330,32 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to float ptcutmin = static_cast(Pt[0]); float ptcutmax = static_cast(Pt[1]); float pt = track.pt(); - if (pt < ptcutmin || pt > ptcutmax) + vector Eta = cfEta.value; + float etacutmin = static_cast(Eta[0]); + float etacutmax = static_cast(Eta[1]); + float eta = track.eta(); + if (pt < ptcutmin || pt > ptcutmax || eta < etacutmin || eta > etacutmax) return false; return true; } + TComplex Q(Int_t n) + { + // Using the fact that Q{-n,p} = Q{n,p}^*. + if (n >= 0) { + return cor.Qvector[n]; + } + return TComplex::Conjugate(cor.Qvector[-n]); + } + + TComplex Four(Int_t n1, Int_t n2, Int_t n3, Int_t n4) + { // Generic four-particle correlation . + TComplex four = Q(n1) * Q(n2) * Q(n3) * Q(n4) - Q(n1 + n2) * Q(n3) * Q(n4) - Q(n2) * Q(n1 + n3) * Q(n4) - Q(n1) * Q(n2 + n3) * Q(n4) + 2. * Q(n1 + n2 + n3) * Q(n4) - Q(n2) * Q(n3) * Q(n1 + n4) + Q(n2 + n3) * Q(n1 + n4) - Q(n1) * Q(n3) * Q(n2 + n4) + Q(n1 + n3) * Q(n2 + n4) + 2. * Q(n3) * Q(n1 + n2 + n4) - Q(n1) * Q(n2) * Q(n3 + n4) + Q(n1 + n2) * Q(n3 + n4) + 2. * Q(n2) * Q(n1 + n3 + n4) + 2. * Q(n1) * Q(n2 + n3 + n4) - 6. * Q(n1 + n2 + n3 + n4); + + return four; + + } // TComplex Four(Int_t n1, Int_t n2, Int_t n3, Int_t n4) + template void Steer(T1 const& collision, T2 const& tracks) { @@ -316,37 +364,40 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to return; } // Print current run number: - LOGF(info, "Run number: %d", collision.bc().runNumber()); - // Print centrality estimated with "FT0M" estimator: - LOGF(info, "Centrality: %f", collision.centFT0M()); - // Print vertex X position: - LOGF(info, "Vertex X position: %f", collision.posX()); + // LOGF(info, "Run number: %d", collision.bc().runNumber()); + + float zrec = 0., zsim = 0., centr = 0, M = 0.; + + float v22, v32, v42; + float four32, four42; - float zrec = 0., zsim = 0.; if constexpr (rs == eRec || rs == eRecAndSim) { event.fHistX[eRec]->Fill(collision.posX()); event.fHistY[eRec]->Fill(collision.posY()); event.fHistZ[eRec]->Fill(collision.posZ()); event.fEventHistograms[eVertexZ][eRec][0]->Fill(collision.posZ()); zrec = collision.posZ(); - float centr = 0; + event.fHistNContr->Fill(collision.numContrib()); if (cfCent == 1) centr = collision.centFT0C(); - if (cfCent == 2) + else if (cfCent == 2) centr = collision.centFT0M(); - if (cfCent == 3) + else if (cfCent == 3) centr = collision.centFT0A(); event.fHistCentr[eRec]->Fill(centr); - if (cfMult == 1) - event.fHistMult[eRec]->Fill(collision.multTPC()); - if (cfMult == 2) - event.fHistMult[eRec]->Fill(collision.multFV0M()); - if (cfMult == 3) - event.fHistMult[eRec]->Fill(collision.multFT0C()); - if (cfMult == 4) - event.fHistMult[eRec]->Fill(collision.multFT0M()); - if (cfMult == 5) - event.fHistMult[eRec]->Fill(collision.multNTracksPV()); + + std::string multType = "TPC"; + if (cfMult.value == "TPC") + M = collision.multTPC(); + else if (cfMult.value == "FV0M") + M = collision.multFV0M(); + else if (cfMult.value == "FT0C") + M = collision.multFT0C(); + else if (cfMult.value == "FT0M") + M = collision.multFT0M(); + else if (cfMult.value == "NTracksPV") + M = collision.multNTracksPV(); + event.fHistMult[eRec]->Fill(M); if constexpr (rs == eRecAndSim) { auto mccollision = collision.mcCollision(); @@ -358,8 +409,8 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to event.fEventHistograms[eVertexZ][eSim][0]->Fill(mccollision.posZ()); zsim = mccollision.posZ(); event.fHistCentr[eSim]->Fill(centrsim); - event.fQA->Fill(centrsim, centr); - // event.fHistMult[eSim]->Fill(tracks.size()); + qa.fQA->Fill(centrsim, centr); + centr = centrsim; } // *) Event cuts: @@ -371,12 +422,17 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to event.fEventHistograms[eVertexZ][eSim][1]->Fill(zsim); } + // before loop over particles + float eta = 0; + float phi = 0; + for (int ih = 0; ih < maxHarmonic; ih++) { + cor.Qvector[ih] = TComplex(0., 0.); + } + // Main loop over particles: auto track = tracks.iteratorAt(0); // set the type and scope from one instance for (int64_t i = 0; i < tracks.size(); i++) { - // Print track azimuthal angle: - // Fill reconstructed ...: float ptrec = 0., ptsim = 0.; if constexpr (rs == eRec || rs == eRecAndSim) { @@ -384,7 +440,13 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to pc.fHistPt[eRec]->Fill(track.pt()); event.fEventHistograms[ePt][eRec][0]->Fill(track.pt()); ptrec = track.pt(); + eta = track.eta(); + phi = track.phi(); pc.fHistPhi[eRec]->Fill(track.phi()); + pc.fHistCharge[eRec]->Fill(track.sign()); + pc.fHistTPCncls[eRec]->Fill(track.tpcNClsFindable()); + pc.fHistTracksdcaXY[eRec]->Fill(track.dcaXY()); + pc.fHistTracksdcaZ[eRec]->Fill(track.dcaZ()); // ... and corresponding MC truth simulated: // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx @@ -398,8 +460,14 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to pc.fHistPt[eSim]->Fill(mcparticle.pt()); event.fEventHistograms[ePt][eSim][0]->Fill(mcparticle.pt()); ptsim = mcparticle.pt(); + eta = mcparticle.eta(); + phi = mcparticle.phi(); pc.fHistPhi[eSim]->Fill(mcparticle.phi()); - } // end of if constexpr (rs == eRecAndSim) { + // pc.fHistCharge[eSim]->Fill(mcparticle.sign()); + // pc.fHistTPCncls[eSim]->Fill(mcparticle.tpcNClsFindable()); + // pc.fHistTracksdcaXY[eSim]->Fill(mcparticle.dcaXY()); + // pc.fHistTracksdcaZ[eSim]->Fill(mcparticle.dcaZ()); + } // end of if constexpr (rs == eRecAndSim) // *) Particle cuts: if (!ParticleCuts(track)) { // Main call for particle cuts. @@ -409,10 +477,27 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to if constexpr (rs == eRecAndSim) event.fEventHistograms[ePt][eSim][0]->Fill(ptsim); - } // if constexpr (rs == eRec || rs == eRecAndSim) { - } // end of for (int64_t i = 0; i < tracks.size(); i++) { + } // if constexpr (rs == eRec || rs == eRecAndSim) - } // end of template void Steer(T1 const& collision, T2 const& tracks) { + // analysis in the loop over particle + for (int ih = 0; ih < maxHarmonic; ih++) { + cor.Qvector[ih] += TComplex(TMath::Cos(ih * phi), TMath::Sin(ih * phi)); + } + } // end of for (int64_t i = 0; i < tracks.size(); i++) + // calculate correlations + four32 = Four(3, 2, -3, -2).Re() / Four(0, 0, 0, 0).Re(); + four42 = Four(4, 2, -4, -2).Re() / Four(0, 0, 0, 0).Re(); + v22 = (Q(2).Rho2() - M) / (M * (M - 1.)); + v32 = (Q(3).Rho2() - M) / (M * (M - 1.)); + v42 = (Q(4).Rho2() - M) / (M * (M - 1.)); + + cor.pv22_centr->Fill(centr, v22, M * (M - 1)); + cor.pv32_centr->Fill(centr, v32, M * (M - 1)); + cor.pv42_centr->Fill(centr, v42, M * (M - 1)); + cor.pfour32_centr->Fill(centr, four32, M * (M - 1)); + cor.pfour42_centr->Fill(centr, four42, M * (M - 1)); + + } // end of template void Steer(T1 const& collision, T2 const& tracks) // *) Initialize and book all objects: void init(InitContext&) @@ -443,6 +528,16 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to event.fEventHistogramsList->SetOwner(true); fBaseList->Add(event.fEventHistogramsList); + qa.fQAList = new TList(); + qa.fQAList->SetName("QAHistograms"); + qa.fQAList->SetOwner(true); + fBaseList->Add(qa.fQAList); + + cor.fCorrelationVariablesList = new TList(); + cor.fCorrelationVariablesList->SetName("CorrelationVariables"); + cor.fCorrelationVariablesList->SetOwner(true); + fBaseList->Add(cor.fCorrelationVariablesList); + // *) Book pt distribution with binning defined through configurables in the json file: vector l_pt_bins = cf_pt_bins.value; // define local array and initialize it from an array set in the configurables vector l_phi_bins = cf_phi_bins.value; @@ -451,6 +546,10 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to vector l_y_bins = cf_y_bins.value; vector l_z_bins = cf_z_bins.value; vector l_mult_bins = cf_mult_bins.value; + vector l_tpcncls_bins = cf_tpcncls_bins.value; + vector l_dcaxy_bins = cf_dcaxy_bins.value; + vector l_dcaz_bins = cf_dcaz_bins.value; + vector l_ncontr_bins = cf_ncontr_bins.value; int nBins = static_cast(l_pt_bins[0]); int nBinsphi = static_cast(l_phi_bins[0]); int nBinscentr = static_cast(l_centr_bins[0]); @@ -458,6 +557,11 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to int nBinsy = static_cast(l_y_bins[0]); int nBinsz = static_cast(l_z_bins[0]); int nBinsmult = static_cast(l_mult_bins[0]); + int nBinscharge = 2; + int nBinstpcncls = static_cast(l_tpcncls_bins[0]); + int nBinsdcaxy = static_cast(l_dcaxy_bins[0]); + int nBinsdcaz = static_cast(l_dcaz_bins[0]); + int nBinsncontr = static_cast(l_ncontr_bins[0]); float min = l_pt_bins[1]; float max = l_pt_bins[2]; @@ -473,20 +577,54 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to float maxz = l_z_bins[2]; float minmult = l_mult_bins[1]; float maxmult = l_mult_bins[2]; + float mincharge = -2.; + float maxcharge = 2.; + float mintpcncls = l_tpcncls_bins[1]; + float maxtpcncls = l_tpcncls_bins[2]; + float mindcaxy = l_dcaxy_bins[1]; + float maxdcaxy = l_dcaxy_bins[2]; + float mindcaz = l_dcaz_bins[1]; + float maxdcaz = l_dcaz_bins[2]; + float maxncontr = l_ncontr_bins[1]; + float minncontr = l_ncontr_bins[2]; pc.fHistPt[eRec] = new TH1F("fHistPt[eRec]", "pt distribution for reconstructed particles", nBins, min, max); - pc.fHistPt[eRec]->GetXaxis()->SetTitle("p_{T}"); - pc.fParticleHistogramsList->Add(pc.fHistPt[eRec]); pc.fHistPhi[eRec] = new TH1F("fHistPhi[eRec]", "phi distribution for reconstructed particles", nBinsphi, minphi, maxphi); + pc.fHistCharge[eRec] = new TH1F("fHistCharge[eRec]", "charge distribution for reconstructed particles", nBinscharge, mincharge, maxcharge); + pc.fHistTPCncls[eRec] = new TH1F("fHistTPCncls[eRec]", "tpcncls distribution for reconstructed particles", nBinstpcncls, mintpcncls, maxtpcncls); + pc.fHistTracksdcaXY[eRec] = new TH1F("fHistTracksdcaXY[eRec]", "dcaxy distribution for reconstructed particles", nBinsdcaxy, mindcaxy, maxdcaxy); + pc.fHistTracksdcaZ[eRec] = new TH1F("fHistTracksdcaZ[eRec]", "dcaz distribution for reconstructed particles", nBinsdcaz, mindcaz, maxdcaz); + pc.fHistPt[eRec]->GetXaxis()->SetTitle("p_{T}"); pc.fHistPhi[eRec]->GetXaxis()->SetTitle("phi"); + pc.fHistCharge[eRec]->GetXaxis()->SetTitle("charge"); + pc.fHistTPCncls[eRec]->GetXaxis()->SetTitle("TPCNClsFindable"); + pc.fHistTracksdcaXY[eRec]->GetXaxis()->SetTitle("DCA XY"); + pc.fHistTracksdcaZ[eRec]->GetXaxis()->SetTitle("DCA Z"); + pc.fParticleHistogramsList->Add(pc.fHistPt[eRec]); pc.fParticleHistogramsList->Add(pc.fHistPhi[eRec]); + pc.fParticleHistogramsList->Add(pc.fHistCharge[eRec]); + pc.fParticleHistogramsList->Add(pc.fHistTPCncls[eRec]); + pc.fParticleHistogramsList->Add(pc.fHistTracksdcaXY[eRec]); + pc.fParticleHistogramsList->Add(pc.fHistTracksdcaZ[eRec]); pc.fHistPt[eSim] = new TH1F("fHistPt[eSim]", "pt distribution for simulated particles", nBins, min, max); - pc.fHistPt[eSim]->GetXaxis()->SetTitle("p_{T}"); - pc.fParticleHistogramsList->Add(pc.fHistPt[eSim]); pc.fHistPhi[eSim] = new TH1F("fHistPhi[eSim]", "phi distribution for simulated particles", nBinsphi, minphi, maxphi); + pc.fHistCharge[eSim] = new TH1F("fHistCharge[eSim]", "charge distribution for simulated particles", nBinscharge, mincharge, maxcharge); + pc.fHistTPCncls[eSim] = new TH1F("fHistTPCncls[eSim]", "tpcncls distribution for simulated particles", nBinstpcncls, minphi, maxtpcncls); + pc.fHistTracksdcaXY[eSim] = new TH1F("fHistTracksdcaXY[eSim]", "dcaxy distribution for simulated particles", nBinsdcaxy, mindcaxy, maxdcaxy); + pc.fHistTracksdcaZ[eSim] = new TH1F("fHistTracksdcaZ[eSim]", "dcaz distribution for simulated particles", nBinsdcaz, mindcaz, maxdcaz); + pc.fHistPt[eSim]->GetXaxis()->SetTitle("p_{T}"); pc.fHistPhi[eSim]->GetXaxis()->SetTitle("phi"); + pc.fHistCharge[eSim]->GetXaxis()->SetTitle("charge"); + pc.fHistTPCncls[eSim]->GetXaxis()->SetTitle("TPCNClsFindable"); + pc.fHistTracksdcaXY[eSim]->GetXaxis()->SetTitle("DCA XY"); + pc.fHistTracksdcaZ[eSim]->GetXaxis()->SetTitle("DCA Z"); + pc.fParticleHistogramsList->Add(pc.fHistPt[eSim]); pc.fParticleHistogramsList->Add(pc.fHistPhi[eSim]); + pc.fParticleHistogramsList->Add(pc.fHistCharge[eSim]); + pc.fParticleHistogramsList->Add(pc.fHistTPCncls[eSim]); + pc.fParticleHistogramsList->Add(pc.fHistTracksdcaXY[eSim]); + pc.fParticleHistogramsList->Add(pc.fHistTracksdcaZ[eSim]); pc.histWeights = GetHistogramWithWeights(cfFileWithWeights.value.c_str(), "000123456"); pc.fParticleHistogramsList->Add(pc.histWeights); @@ -496,16 +634,19 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to event.fHistY[eRec] = new TH1F("fHistY[eRec]", "posY distribution for reconstructed particles", nBinsy, miny, maxy); event.fHistZ[eRec] = new TH1F("fHistZ[eRec]", "posZ distribution for reconstructed particles", nBinsz, minz, maxz); event.fHistMult[eRec] = new TH1I("fHistMult[eRec]", "mult distribution for reconstructed particles", nBinsmult, minmult, maxmult); + event.fHistNContr = new TH1I("fHistNContr", "NContr distribution", nBinsncontr, minncontr, maxncontr); event.fHistCentr[eRec]->GetXaxis()->SetTitle("centrality"); event.fHistX[eRec]->GetXaxis()->SetTitle("x"); event.fHistY[eRec]->GetXaxis()->SetTitle("y"); event.fHistZ[eRec]->GetXaxis()->SetTitle("z"); event.fHistMult[eRec]->GetXaxis()->SetTitle("multiplicity"); + event.fHistNContr->GetXaxis()->SetTitle("numContrib"); event.fEventHistogramsList->Add(event.fHistCentr[eRec]); event.fEventHistogramsList->Add(event.fHistX[eRec]); event.fEventHistogramsList->Add(event.fHistY[eRec]); event.fEventHistogramsList->Add(event.fHistZ[eRec]); event.fEventHistogramsList->Add(event.fHistMult[eRec]); + event.fEventHistogramsList->Add(event.fHistNContr); event.fHistCentr[eSim] = new TH1F("fHistCentr[eSim]", "centrality distribution for simulated particles", nBinscentr, mincentr, maxcentr); event.fHistX[eSim] = new TH1F("fHistX[eSim]", "posX distribution for simulated particles", nBinsx, minx, maxx); @@ -541,11 +682,29 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to } } - event.fQA = new TH2F("QA", "quality assurance", nBinscentr, mincentr, maxcentr, nBinscentr, mincentr, maxcentr); + qa.fQA = new TH2F("QA", "quality assurance", nBinscentr, mincentr, maxcentr, nBinscentr, mincentr, maxcentr); if (cfQA) { - event.fEventHistogramsList->Add(event.fQA); + qa.fQAList->Add(qa.fQA); } + // float quantiles[10] = {0, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8}; + float quantiles[10] = {0, 5, 10, 20, 30, 40, 50, 60, 70, 80}; + cor.pv22_centr = new TProfile("pv22", "profile of v2^2", 9, quantiles); + cor.pv32_centr = new TProfile("pv32", "profile of v3^2", 9, quantiles); + cor.pv42_centr = new TProfile("pv42", "profile of v4^2", 9, quantiles); + cor.pfour32_centr = new TProfile("pfour32", "profile of v2^2*v3^2", 9, quantiles); + cor.pfour42_centr = new TProfile("pfour32", "profile of v2^2*v4^2", 9, quantiles); + cor.pv22_centr->GetXaxis()->SetTitle("v_{2}^{2}"); + cor.pv32_centr->GetXaxis()->SetTitle("v_{3}^{2}"); + cor.pv42_centr->GetXaxis()->SetTitle("v_{4}^{2}"); + cor.pfour32_centr->GetXaxis()->SetTitle("v_{2}^{2}v_{3}^{2}"); + cor.pfour42_centr->GetXaxis()->SetTitle("v_{2}^{2}v_{4}^{2}"); + cor.fCorrelationVariablesList->Add(cor.pv22_centr); + cor.fCorrelationVariablesList->Add(cor.pv32_centr); + cor.fCorrelationVariablesList->Add(cor.pv42_centr); + cor.fCorrelationVariablesList->Add(cor.pfour32_centr); + cor.fCorrelationVariablesList->Add(cor.pfour42_centr); + } // end of void init(InitContext&) { // A) Process only reconstructed data: From f7deee2c099778e54b762c8beb4e689d22eb79da Mon Sep 17 00:00:00 2001 From: Pengchong Hu Date: Tue, 26 May 2026 22:39:25 +0200 Subject: [PATCH 09/11] multiharmoniccorrelations --- .../Tasks/multiharmonicCorrelations.cxx | 252 ++++++++++++++---- 1 file changed, 200 insertions(+), 52 deletions(-) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx index 5ea45627e26..3aba74e9d35 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx @@ -15,26 +15,16 @@ #include "Common/DataModel/TrackSelectionTables.h" // needed for aod::TracksDCA table #include -#include #include -#include #include -#include -#include -#include +#include #include -#include -#include +#include #include -#include -#include -#include -#include -#include +#include #include -#include #include #include #include @@ -88,20 +78,25 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to Configurable cfDryRun{"cfDryRun", false, "book all histos and run without filling and calculating anything"}; // example for built-in type (float, string, etc.) Configurable> cf_pt_bins{"cf_pt_bins", {1000, 0., 100.}, "nPtBins, ptMin, ptMax"}; // example for an array Configurable> cf_phi_bins{"cf_phi_bins", {100, 0., o2::constants::math::TwoPI}, "nPhiBins, phiMin, phiMax"}; - Configurable> cf_centr_bins{"cf_centr_bins", {1000, 0., 100.}, "nCentrBins, centrMin, centrMax"}; + Configurable> cf_centr_bins{"cf_centr_bins", {100, 0., 100.}, "nCentrBins, centrMin, centrMax"}; Configurable> cf_x_bins{"cf_x_bins", {1000, -100., 100.}, "nXBins, xMin, xMax"}; Configurable> cf_y_bins{"cf_y_bins", {1000, -100., 100.}, "nYBins, yMin, yMax"}; Configurable> cf_z_bins{"cf_z_bins", {1000, -100., 100.}, "nZBins, zMin, zMax"}; Configurable> cf_mult_bins{"cf_mult_bins", {50, 0, 3e3}, "nMultBins, multMin, multMax"}; + Configurable> cf_tpcncls_bins{"cf_tpcncls_bins", {100, 0., 1000.}, "ntpcnclsBins, tpnclsMin, tpcnclsMax"}; + Configurable> cf_dcaxy_bins{"cf_dcaxy_bins", {1000, -20., 20.}, "ndcaxyBins, dcaxyMin, dcaxyMax"}; + Configurable> cf_dcaz_bins{"cf_dcaz_bins", {1000, -10., 10.}, "ndcazBins, dcazMin, dcazMax"}; + Configurable> cf_ncontr_bins{"cf_ncontr_bins", {100, 0., 1000}, "nNContrBins, NContrMin, NContrMax"}; Configurable cfCent{"cfCent", 1, "centrality estimator"}; - Configurable cfMult{"cfMult", 1, "multiplicity"}; + Configurable cfMult{"cfMult", "TPC", "multiplicity"}; Configurable cfQA{"cfQA", true, "quality assurance"}; Configurable> cfVertexZ{"cfVertexZ", {-10, 10.}, "vertex z position range: {min, max}[cm], with convention: min <= Vz < max"}; Configurable> cfPt{"cfPt", {0.2, 5.0}, "transverse momentum range"}; + Configurable> cfEta{"cfEta", {-0.8, 0.8}, "eta range"}; - Configurable cfFileWithWeights{"cfFileWithWeights", "~/O2/weights.root", "path to external ROOT file which holds all particle weights"}; + Configurable cfFileWithWeights{"cfFileWithWeights", "/alice-ccdb.cern.ch/Users/p/pengchon/test04", "path to external ROOT file which holds all particle weights"}; // *) Define and initialize all data members to be called in the main process* functions: // **) Task configuration: @@ -115,6 +110,10 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to TList* fParticleHistogramsList = NULL; //!Getenv("USER"), "", ""); // do not forget to add #include to the preamble of your analysis task @@ -302,7 +318,7 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to float vertexZmin = static_cast(vertexZ[0]); float vertexZmax = static_cast(vertexZ[1]); float posZ = collision.posZ(); - if (posZ < vertexZmin || posZ > vertexZmax) + if (posZ < vertexZmin || posZ > vertexZmax || (!collision.sel8())) return false; return true; } @@ -314,11 +330,32 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to float ptcutmin = static_cast(Pt[0]); float ptcutmax = static_cast(Pt[1]); float pt = track.pt(); - if (pt < ptcutmin || pt > ptcutmax) + vector Eta = cfEta.value; + float etacutmin = static_cast(Eta[0]); + float etacutmax = static_cast(Eta[1]); + float eta = track.eta(); + if (pt < ptcutmin || pt > ptcutmax || eta < etacutmin || eta > etacutmax) return false; return true; } + TComplex Q(Int_t n) + { + // Using the fact that Q{-n,p} = Q{n,p}^*. + if (n >= 0) { + return cor.Qvector[n]; + } + return TComplex::Conjugate(cor.Qvector[-n]); + } + + TComplex Four(Int_t n1, Int_t n2, Int_t n3, Int_t n4) + { // Generic four-particle correlation . + TComplex four = Q(n1) * Q(n2) * Q(n3) * Q(n4) - Q(n1 + n2) * Q(n3) * Q(n4) - Q(n2) * Q(n1 + n3) * Q(n4) - Q(n1) * Q(n2 + n3) * Q(n4) + 2. * Q(n1 + n2 + n3) * Q(n4) - Q(n2) * Q(n3) * Q(n1 + n4) + Q(n2 + n3) * Q(n1 + n4) - Q(n1) * Q(n3) * Q(n2 + n4) + Q(n1 + n3) * Q(n2 + n4) + 2. * Q(n3) * Q(n1 + n2 + n4) - Q(n1) * Q(n2) * Q(n3 + n4) + Q(n1 + n2) * Q(n3 + n4) + 2. * Q(n2) * Q(n1 + n3 + n4) + 2. * Q(n1) * Q(n2 + n3 + n4) - 6. * Q(n1 + n2 + n3 + n4); + + return four; + + } // TComplex Four(Int_t n1, Int_t n2, Int_t n3, Int_t n4) + template void Steer(T1 const& collision, T2 const& tracks) { @@ -327,37 +364,40 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to return; } // Print current run number: - LOGF(info, "Run number: %d", collision.bc().runNumber()); - // Print centrality estimated with "FT0M" estimator: - LOGF(info, "Centrality: %f", collision.centFT0M()); - // Print vertex X position: - LOGF(info, "Vertex X position: %f", collision.posX()); + // LOGF(info, "Run number: %d", collision.bc().runNumber()); + + float zrec = 0., zsim = 0., centr = 0, M = 0.; + + float v22, v32, v42; + float four32, four42; - float zrec = 0., zsim = 0.; if constexpr (rs == eRec || rs == eRecAndSim) { event.fHistX[eRec]->Fill(collision.posX()); event.fHistY[eRec]->Fill(collision.posY()); event.fHistZ[eRec]->Fill(collision.posZ()); event.fEventHistograms[eVertexZ][eRec][0]->Fill(collision.posZ()); zrec = collision.posZ(); - float centr = 0; + event.fHistNContr->Fill(collision.numContrib()); if (cfCent == 1) centr = collision.centFT0C(); - if (cfCent == 2) + else if (cfCent == 2) centr = collision.centFT0M(); - if (cfCent == 3) + else if (cfCent == 3) centr = collision.centFT0A(); event.fHistCentr[eRec]->Fill(centr); - if (cfMult == 1) - event.fHistMult[eRec]->Fill(collision.multTPC()); - if (cfMult == 2) - event.fHistMult[eRec]->Fill(collision.multFV0M()); - if (cfMult == 3) - event.fHistMult[eRec]->Fill(collision.multFT0C()); - if (cfMult == 4) - event.fHistMult[eRec]->Fill(collision.multFT0M()); - if (cfMult == 5) - event.fHistMult[eRec]->Fill(collision.multNTracksPV()); + + std::string multType = "TPC"; + if (cfMult.value == "TPC") + M = collision.multTPC(); + else if (cfMult.value == "FV0M") + M = collision.multFV0M(); + else if (cfMult.value == "FT0C") + M = collision.multFT0C(); + else if (cfMult.value == "FT0M") + M = collision.multFT0M(); + else if (cfMult.value == "NTracksPV") + M = collision.multNTracksPV(); + event.fHistMult[eRec]->Fill(M); if constexpr (rs == eRecAndSim) { auto mccollision = collision.mcCollision(); @@ -369,8 +409,8 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to event.fEventHistograms[eVertexZ][eSim][0]->Fill(mccollision.posZ()); zsim = mccollision.posZ(); event.fHistCentr[eSim]->Fill(centrsim); - event.fQA->Fill(centrsim, centr); - // event.fHistMult[eSim]->Fill(tracks.size()); + qa.fQA->Fill(centrsim, centr); + centr = centrsim; } // *) Event cuts: @@ -382,12 +422,17 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to event.fEventHistograms[eVertexZ][eSim][1]->Fill(zsim); } + // before loop over particles + float eta = 0; + float phi = 0; + for (int ih = 0; ih < maxHarmonic; ih++) { + cor.Qvector[ih] = TComplex(0., 0.); + } + // Main loop over particles: auto track = tracks.iteratorAt(0); // set the type and scope from one instance for (int64_t i = 0; i < tracks.size(); i++) { - // Print track azimuthal angle: - // Fill reconstructed ...: float ptrec = 0., ptsim = 0.; if constexpr (rs == eRec || rs == eRecAndSim) { @@ -395,7 +440,13 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to pc.fHistPt[eRec]->Fill(track.pt()); event.fEventHistograms[ePt][eRec][0]->Fill(track.pt()); ptrec = track.pt(); + eta = track.eta(); + phi = track.phi(); pc.fHistPhi[eRec]->Fill(track.phi()); + pc.fHistCharge[eRec]->Fill(track.sign()); + pc.fHistTPCncls[eRec]->Fill(track.tpcNClsFindable()); + pc.fHistTracksdcaXY[eRec]->Fill(track.dcaXY()); + pc.fHistTracksdcaZ[eRec]->Fill(track.dcaZ()); // ... and corresponding MC truth simulated: // See https://github.com/AliceO2Group/O2Physics/blob/master/Tutorials/src/mcHistograms.cxx @@ -409,8 +460,14 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to pc.fHistPt[eSim]->Fill(mcparticle.pt()); event.fEventHistograms[ePt][eSim][0]->Fill(mcparticle.pt()); ptsim = mcparticle.pt(); + eta = mcparticle.eta(); + phi = mcparticle.phi(); pc.fHistPhi[eSim]->Fill(mcparticle.phi()); - } // end of if constexpr (rs == eRecAndSim) { + // pc.fHistCharge[eSim]->Fill(mcparticle.sign()); + // pc.fHistTPCncls[eSim]->Fill(mcparticle.tpcNClsFindable()); + // pc.fHistTracksdcaXY[eSim]->Fill(mcparticle.dcaXY()); + // pc.fHistTracksdcaZ[eSim]->Fill(mcparticle.dcaZ()); + } // end of if constexpr (rs == eRecAndSim) // *) Particle cuts: if (!ParticleCuts(track)) { // Main call for particle cuts. @@ -420,10 +477,27 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to if constexpr (rs == eRecAndSim) event.fEventHistograms[ePt][eSim][0]->Fill(ptsim); - } // if constexpr (rs == eRec || rs == eRecAndSim) { - } // end of for (int64_t i = 0; i < tracks.size(); i++) { + } // if constexpr (rs == eRec || rs == eRecAndSim) - } // end of template void Steer(T1 const& collision, T2 const& tracks) { + // analysis in the loop over particle + for (int ih = 0; ih < maxHarmonic; ih++) { + cor.Qvector[ih] += TComplex(TMath::Cos(ih * phi), TMath::Sin(ih * phi)); + } + } // end of for (int64_t i = 0; i < tracks.size(); i++) + // calculate correlations + four32 = Four(3, 2, -3, -2).Re() / Four(0, 0, 0, 0).Re(); + four42 = Four(4, 2, -4, -2).Re() / Four(0, 0, 0, 0).Re(); + v22 = (Q(2).Rho2() - M) / (M * (M - 1.)); + v32 = (Q(3).Rho2() - M) / (M * (M - 1.)); + v42 = (Q(4).Rho2() - M) / (M * (M - 1.)); + + cor.pv22_centr->Fill(centr, v22, M * (M - 1)); + cor.pv32_centr->Fill(centr, v32, M * (M - 1)); + cor.pv42_centr->Fill(centr, v42, M * (M - 1)); + cor.pfour32_centr->Fill(centr, four32, M * (M - 1)); + cor.pfour42_centr->Fill(centr, four42, M * (M - 1)); + + } // end of template void Steer(T1 const& collision, T2 const& tracks) // *) Initialize and book all objects: void init(InitContext&) @@ -454,6 +528,16 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to event.fEventHistogramsList->SetOwner(true); fBaseList->Add(event.fEventHistogramsList); + qa.fQAList = new TList(); + qa.fQAList->SetName("QAHistograms"); + qa.fQAList->SetOwner(true); + fBaseList->Add(qa.fQAList); + + cor.fCorrelationVariablesList = new TList(); + cor.fCorrelationVariablesList->SetName("CorrelationVariables"); + cor.fCorrelationVariablesList->SetOwner(true); + fBaseList->Add(cor.fCorrelationVariablesList); + // *) Book pt distribution with binning defined through configurables in the json file: vector l_pt_bins = cf_pt_bins.value; // define local array and initialize it from an array set in the configurables vector l_phi_bins = cf_phi_bins.value; @@ -462,6 +546,10 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to vector l_y_bins = cf_y_bins.value; vector l_z_bins = cf_z_bins.value; vector l_mult_bins = cf_mult_bins.value; + vector l_tpcncls_bins = cf_tpcncls_bins.value; + vector l_dcaxy_bins = cf_dcaxy_bins.value; + vector l_dcaz_bins = cf_dcaz_bins.value; + vector l_ncontr_bins = cf_ncontr_bins.value; int nBins = static_cast(l_pt_bins[0]); int nBinsphi = static_cast(l_phi_bins[0]); int nBinscentr = static_cast(l_centr_bins[0]); @@ -469,6 +557,11 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to int nBinsy = static_cast(l_y_bins[0]); int nBinsz = static_cast(l_z_bins[0]); int nBinsmult = static_cast(l_mult_bins[0]); + int nBinscharge = 2; + int nBinstpcncls = static_cast(l_tpcncls_bins[0]); + int nBinsdcaxy = static_cast(l_dcaxy_bins[0]); + int nBinsdcaz = static_cast(l_dcaz_bins[0]); + int nBinsncontr = static_cast(l_ncontr_bins[0]); float min = l_pt_bins[1]; float max = l_pt_bins[2]; @@ -484,20 +577,54 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to float maxz = l_z_bins[2]; float minmult = l_mult_bins[1]; float maxmult = l_mult_bins[2]; + float mincharge = -2.; + float maxcharge = 2.; + float mintpcncls = l_tpcncls_bins[1]; + float maxtpcncls = l_tpcncls_bins[2]; + float mindcaxy = l_dcaxy_bins[1]; + float maxdcaxy = l_dcaxy_bins[2]; + float mindcaz = l_dcaz_bins[1]; + float maxdcaz = l_dcaz_bins[2]; + float maxncontr = l_ncontr_bins[1]; + float minncontr = l_ncontr_bins[2]; pc.fHistPt[eRec] = new TH1F("fHistPt[eRec]", "pt distribution for reconstructed particles", nBins, min, max); - pc.fHistPt[eRec]->GetXaxis()->SetTitle("p_{T}"); - pc.fParticleHistogramsList->Add(pc.fHistPt[eRec]); pc.fHistPhi[eRec] = new TH1F("fHistPhi[eRec]", "phi distribution for reconstructed particles", nBinsphi, minphi, maxphi); + pc.fHistCharge[eRec] = new TH1F("fHistCharge[eRec]", "charge distribution for reconstructed particles", nBinscharge, mincharge, maxcharge); + pc.fHistTPCncls[eRec] = new TH1F("fHistTPCncls[eRec]", "tpcncls distribution for reconstructed particles", nBinstpcncls, mintpcncls, maxtpcncls); + pc.fHistTracksdcaXY[eRec] = new TH1F("fHistTracksdcaXY[eRec]", "dcaxy distribution for reconstructed particles", nBinsdcaxy, mindcaxy, maxdcaxy); + pc.fHistTracksdcaZ[eRec] = new TH1F("fHistTracksdcaZ[eRec]", "dcaz distribution for reconstructed particles", nBinsdcaz, mindcaz, maxdcaz); + pc.fHistPt[eRec]->GetXaxis()->SetTitle("p_{T}"); pc.fHistPhi[eRec]->GetXaxis()->SetTitle("phi"); + pc.fHistCharge[eRec]->GetXaxis()->SetTitle("charge"); + pc.fHistTPCncls[eRec]->GetXaxis()->SetTitle("TPCNClsFindable"); + pc.fHistTracksdcaXY[eRec]->GetXaxis()->SetTitle("DCA XY"); + pc.fHistTracksdcaZ[eRec]->GetXaxis()->SetTitle("DCA Z"); + pc.fParticleHistogramsList->Add(pc.fHistPt[eRec]); pc.fParticleHistogramsList->Add(pc.fHistPhi[eRec]); + pc.fParticleHistogramsList->Add(pc.fHistCharge[eRec]); + pc.fParticleHistogramsList->Add(pc.fHistTPCncls[eRec]); + pc.fParticleHistogramsList->Add(pc.fHistTracksdcaXY[eRec]); + pc.fParticleHistogramsList->Add(pc.fHistTracksdcaZ[eRec]); pc.fHistPt[eSim] = new TH1F("fHistPt[eSim]", "pt distribution for simulated particles", nBins, min, max); - pc.fHistPt[eSim]->GetXaxis()->SetTitle("p_{T}"); - pc.fParticleHistogramsList->Add(pc.fHistPt[eSim]); pc.fHistPhi[eSim] = new TH1F("fHistPhi[eSim]", "phi distribution for simulated particles", nBinsphi, minphi, maxphi); + pc.fHistCharge[eSim] = new TH1F("fHistCharge[eSim]", "charge distribution for simulated particles", nBinscharge, mincharge, maxcharge); + pc.fHistTPCncls[eSim] = new TH1F("fHistTPCncls[eSim]", "tpcncls distribution for simulated particles", nBinstpcncls, minphi, maxtpcncls); + pc.fHistTracksdcaXY[eSim] = new TH1F("fHistTracksdcaXY[eSim]", "dcaxy distribution for simulated particles", nBinsdcaxy, mindcaxy, maxdcaxy); + pc.fHistTracksdcaZ[eSim] = new TH1F("fHistTracksdcaZ[eSim]", "dcaz distribution for simulated particles", nBinsdcaz, mindcaz, maxdcaz); + pc.fHistPt[eSim]->GetXaxis()->SetTitle("p_{T}"); pc.fHistPhi[eSim]->GetXaxis()->SetTitle("phi"); + pc.fHistCharge[eSim]->GetXaxis()->SetTitle("charge"); + pc.fHistTPCncls[eSim]->GetXaxis()->SetTitle("TPCNClsFindable"); + pc.fHistTracksdcaXY[eSim]->GetXaxis()->SetTitle("DCA XY"); + pc.fHistTracksdcaZ[eSim]->GetXaxis()->SetTitle("DCA Z"); + pc.fParticleHistogramsList->Add(pc.fHistPt[eSim]); pc.fParticleHistogramsList->Add(pc.fHistPhi[eSim]); + pc.fParticleHistogramsList->Add(pc.fHistCharge[eSim]); + pc.fParticleHistogramsList->Add(pc.fHistTPCncls[eSim]); + pc.fParticleHistogramsList->Add(pc.fHistTracksdcaXY[eSim]); + pc.fParticleHistogramsList->Add(pc.fHistTracksdcaZ[eSim]); pc.histWeights = GetHistogramWithWeights(cfFileWithWeights.value.c_str(), "000123456"); pc.fParticleHistogramsList->Add(pc.histWeights); @@ -507,16 +634,19 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to event.fHistY[eRec] = new TH1F("fHistY[eRec]", "posY distribution for reconstructed particles", nBinsy, miny, maxy); event.fHistZ[eRec] = new TH1F("fHistZ[eRec]", "posZ distribution for reconstructed particles", nBinsz, minz, maxz); event.fHistMult[eRec] = new TH1I("fHistMult[eRec]", "mult distribution for reconstructed particles", nBinsmult, minmult, maxmult); + event.fHistNContr = new TH1I("fHistNContr", "NContr distribution", nBinsncontr, minncontr, maxncontr); event.fHistCentr[eRec]->GetXaxis()->SetTitle("centrality"); event.fHistX[eRec]->GetXaxis()->SetTitle("x"); event.fHistY[eRec]->GetXaxis()->SetTitle("y"); event.fHistZ[eRec]->GetXaxis()->SetTitle("z"); event.fHistMult[eRec]->GetXaxis()->SetTitle("multiplicity"); + event.fHistNContr->GetXaxis()->SetTitle("numContrib"); event.fEventHistogramsList->Add(event.fHistCentr[eRec]); event.fEventHistogramsList->Add(event.fHistX[eRec]); event.fEventHistogramsList->Add(event.fHistY[eRec]); event.fEventHistogramsList->Add(event.fHistZ[eRec]); event.fEventHistogramsList->Add(event.fHistMult[eRec]); + event.fEventHistogramsList->Add(event.fHistNContr); event.fHistCentr[eSim] = new TH1F("fHistCentr[eSim]", "centrality distribution for simulated particles", nBinscentr, mincentr, maxcentr); event.fHistX[eSim] = new TH1F("fHistX[eSim]", "posX distribution for simulated particles", nBinsx, minx, maxx); @@ -552,11 +682,29 @@ struct MultiharmonicCorrelations { // this name is used in lower-case format to } } - event.fQA = new TH2F("QA", "quality assurance", nBinscentr, mincentr, maxcentr, nBinscentr, mincentr, maxcentr); + qa.fQA = new TH2F("QA", "quality assurance", nBinscentr, mincentr, maxcentr, nBinscentr, mincentr, maxcentr); if (cfQA) { - event.fEventHistogramsList->Add(event.fQA); + qa.fQAList->Add(qa.fQA); } + // float quantiles[10] = {0, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8}; + float quantiles[10] = {0, 5, 10, 20, 30, 40, 50, 60, 70, 80}; + cor.pv22_centr = new TProfile("pv22", "profile of v2^2", 9, quantiles); + cor.pv32_centr = new TProfile("pv32", "profile of v3^2", 9, quantiles); + cor.pv42_centr = new TProfile("pv42", "profile of v4^2", 9, quantiles); + cor.pfour32_centr = new TProfile("pfour32", "profile of v2^2*v3^2", 9, quantiles); + cor.pfour42_centr = new TProfile("pfour32", "profile of v2^2*v4^2", 9, quantiles); + cor.pv22_centr->GetXaxis()->SetTitle("v_{2}^{2}"); + cor.pv32_centr->GetXaxis()->SetTitle("v_{3}^{2}"); + cor.pv42_centr->GetXaxis()->SetTitle("v_{4}^{2}"); + cor.pfour32_centr->GetXaxis()->SetTitle("v_{2}^{2}v_{3}^{2}"); + cor.pfour42_centr->GetXaxis()->SetTitle("v_{2}^{2}v_{4}^{2}"); + cor.fCorrelationVariablesList->Add(cor.pv22_centr); + cor.fCorrelationVariablesList->Add(cor.pv32_centr); + cor.fCorrelationVariablesList->Add(cor.pv42_centr); + cor.fCorrelationVariablesList->Add(cor.pfour32_centr); + cor.fCorrelationVariablesList->Add(cor.pfour42_centr); + } // end of void init(InitContext&) { // A) Process only reconstructed data: From c0d3d3ac1f000890458f285a382ec75e0b2aaf92 Mon Sep 17 00:00:00 2001 From: Pengchong Hu Date: Wed, 27 May 2026 13:03:25 +0200 Subject: [PATCH 10/11] fix for build and headfiles --- .../Tasks/CMakeLists.txt | 3 --- .../Tasks/multiharmonicCorrelations.cxx | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt b/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt index 8ec9682e286..92142003385 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt +++ b/PWGCF/MultiparticleCorrelations/Tasks/CMakeLists.txt @@ -28,11 +28,8 @@ o2physics_add_dpl_workflow(multiharmonic-correlations SOURCES multiharmonicCorrelations.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) -<<<<<<< HEAD o2physics_add_dpl_workflow(multiparticle-cumulants SOURCES multiparticleCumulants.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::PWGCFCore COMPONENT_NAME Analysis) -======= ->>>>>>> fb3e94cf1176f17e0ef923e20450f3148807bddf diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx index 3aba74e9d35..6cbe4d21241 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx @@ -15,16 +15,27 @@ #include "Common/DataModel/TrackSelectionTables.h" // needed for aod::TracksDCA table #include +#include #include +#include #include -#include +#include +#include +#include #include +#include +#include #include #include -#include +#include +#include +#include +#include +#include #include +#include #include #include #include From c39aea043c16444d2002eeb427ff9db187e05172 Mon Sep 17 00:00:00 2001 From: Pengchong Hu Date: Wed, 27 May 2026 13:07:18 +0200 Subject: [PATCH 11/11] fix for format --- .../Tasks/multiharmonicCorrelations.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx index 6cbe4d21241..d19e1b7233c 100644 --- a/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx +++ b/PWGCF/MultiparticleCorrelations/Tasks/multiharmonicCorrelations.cxx @@ -25,8 +25,8 @@ #include #include -#include #include +#include #include #include #include