diff --git a/Analysis/Tasks/PWGCF/CMakeLists.txt b/Analysis/Tasks/PWGCF/CMakeLists.txt index 28ab35144fd01..f634377aa3890 100644 --- a/Analysis/Tasks/PWGCF/CMakeLists.txt +++ b/Analysis/Tasks/PWGCF/CMakeLists.txt @@ -10,6 +10,7 @@ # or submit itself to any jurisdiction. add_subdirectory(FemtoDream) +add_subdirectory(GenericFramework) o2_add_library(PWGCFCore SOURCES AnalysisConfigurableCuts.cxx diff --git a/Analysis/Tasks/PWGCF/GenericFramework/CMakeLists.txt b/Analysis/Tasks/PWGCF/GenericFramework/CMakeLists.txt new file mode 100644 index 0000000000000..0eaaf14b09fb5 --- /dev/null +++ b/Analysis/Tasks/PWGCF/GenericFramework/CMakeLists.txt @@ -0,0 +1,31 @@ +# 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. + +o2_add_library(GenericFramework + SOURCES src/GFWCumulant.cxx + src/GFW.cxx + src/ProfileSubset.cxx + src/FlowContainer.cxx + src/GFWWeights.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisDataModel) + +o2_target_root_dictionary(GenericFramework + HEADERS include/GenericFramework/GFWCumulant.h + include/GenericFramework/GFW.h + include/GenericFramework/ProfileSubset.h + include/GenericFramework/FlowContainer.h + include/GenericFramework/GFWWeights.h + LINKDEF src/GenericFrameworkLinkDef.h) + +o2_add_dpl_workflow(flow-generic-framework + SOURCES GenericFramework.cxx + PUBLIC_LINK_LIBRARIES O2::Framework O2::AnalysisCore O2::GenericFramework + COMPONENT_NAME Analysis) \ No newline at end of file diff --git a/Analysis/Tasks/PWGCF/GenericFramework/GenericFramework.cxx b/Analysis/Tasks/PWGCF/GenericFramework/GenericFramework.cxx new file mode 100644 index 0000000000000..a24e5d91e7493 --- /dev/null +++ b/Analysis/Tasks/PWGCF/GenericFramework/GenericFramework.cxx @@ -0,0 +1,191 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// 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. +// +/// \brief Implementation of the Generic Framework for flow measurements in O2 +/// \author Emil Gorm Nielsen +/// \since 19-07-2021 + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoAHelpers.h" +#include "Framework/RunningWorkflowInfo.h" + +#include "AnalysisDataModel/EventSelection.h" +#include "AnalysisDataModel/TrackSelectionTables.h" +#include "AnalysisDataModel/Centrality.h" + +#include +#include + +#include "Framework/HistogramRegistry.h" +#include "GenericFramework/GFW.h" +#include "GenericFramework/GFWCumulant.h" +#include "GenericFramework/FlowContainer.h" +#include "GenericFramework/GFWWeights.h" +#include +#include + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +#define O2_DEFINE_CONFIGURABLE(NAME, TYPE, DEFAULT, HELP) Configurable NAME{#NAME, DEFAULT, HELP}; + +struct GenericFramework { + + O2_DEFINE_CONFIGURABLE(cfgCutVertex, float, 10.0f, "Accepted z-vertex range") + O2_DEFINE_CONFIGURABLE(cfgCutPtMin, float, 0.2f, "Minimal pT for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutPtMax, float, 3.0f, "Maximal pT for tracks") + O2_DEFINE_CONFIGURABLE(cfgCutEta, float, 0.8f, "Eta range for tracks") + + O2_DEFINE_CONFIGURABLE(cfgEfficiency, std::string, "", "CCDB path to efficiency object") + O2_DEFINE_CONFIGURABLE(cfgAcceptance, std::string, "", "CCDB path to acceptance object") + + ConfigurableAxis axisVertex{"axisVertex", {20, -10, 10}, "vertex axis for histograms"}; + ConfigurableAxis axisPhi{"axisPhi", {60, 0.0, 2. * M_PI}, "phi axis for histograms"}; + ConfigurableAxis axisEta{"axisEta", {40, -1., 1.}, "eta axis for histograms"}; + ConfigurableAxis axisPt{"axisPt", {VARIABLE_WIDTH, 0.2, 0.25, 0.30, 0.40, 0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90, 2.00, 2.20, 2.40, 2.60, 2.80, 3.00}, "pt axis for histograms"}; + ConfigurableAxis axisMultiplicity{"axisMultiplicity", {VARIABLE_WIDTH, 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100.1}, "multiplicity / centrality axis for histograms"}; + + Filter collisionFilter = nabs(aod::collision::posZ) < cfgCutVertex; + Filter trackFilter = (nabs(aod::track::eta) < cfgCutEta) && (aod::track::pt > cfgCutPtMin) && (aod::track::pt < cfgCutPtMax) && ((aod::track::isGlobalTrack == (uint8_t) true) || (aod::track::isGlobalTrackSDD == (uint8_t) true)); + using myTracks = soa::Filtered>; + + //Connect to ccdb + Service ccdb; + Configurable nolaterthan{"ccdb-no-later-than", std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), "latest acceptable timestamp of creation for the object"}; + Configurable url{"ccdb-url", "http://ccdb-test.cern.ch:8080", "url of the ccdb repository"}; + + struct Config { + TH1D* mEfficiency = nullptr; + GFWWeights* mAcceptance = nullptr; + } cfg; + + //Define output + OutputObj fFC{FlowContainer("FlowContainer")}; + HistogramRegistry registry{"registry"}; + + // define global variables + GFW* fGFW = new GFW(); + std::vector corrconfigs; + + TRandom3* fRndm = new TRandom3(0); + + void init(InitContext const&) + { + + ccdb->setURL(url.value); + ccdb->setCaching(true); + ccdb->setCreatedNotAfter(nolaterthan.value); + + //Global effiencies + if (cfgEfficiency.value.empty() == false) { + cfg.mEfficiency = ccdb->getForTimeStamp(cfgEfficiency.value, nolaterthan.value); + if (cfg.mEfficiency) + LOGF(info, "Loaded efficiency histogram %s (%p)", cfgEfficiency.value.c_str(), (void*)cfg.mEfficiency); + else + LOGF(info, "Loaded efficiency histogram %s (%p)", cfgEfficiency.value.c_str(), (void*)cfg.mEfficiency); + } + + registry.add("hPhi", "", {HistType::kTH1D, {axisPhi}}); + registry.add("hEta", "", {HistType::kTH1D, {axisEta}}); + registry.add("hVtxZ", "", {HistType::kTH1D, {axisVertex}}); + Int_t pows[7] = {3, 0, 2, 2, 3, 3, 3}; + Int_t powsFull[7] = {5, 0, 4, 4, 3, 3, 3}; + + fGFW->AddRegion("refN", 7, pows, -0.8, -0.4, 1, 1); + fGFW->AddRegion("refP", 7, pows, 0.4, 0.8, 1, 1); + fGFW->AddRegion("full", 7, powsFull, -0.8, 0.8, 1, 2); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refP {2} refN {-2}", "ChGap22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refP {2 2} refN {-2 -2}", "ChGap24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 -2}", "ChFull22", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("full {2 2 -2 -2}", "ChFull24", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refP {3} refN {-3}", "ChGap32", kFALSE)); + corrconfigs.push_back(fGFW->GetCorrelatorConfig("refP {4} refN {-4}", "ChGap42", kFALSE)); + + TObjArray* oba = new TObjArray(); + oba->Add(new TNamed("ChGap22", "ChGap22")); //for gap (|eta|>0.4) case + oba->Add(new TNamed("ChGap24", "ChGap24")); //for gap (|eta|>0.4) case + oba->Add(new TNamed("ChFull22", "ChFull22")); //no-gap case + oba->Add(new TNamed("ChFull24", "ChFull24")); //no-gap case + oba->Add(new TNamed("ChGap32", "ChGap32")); //gap-case + oba->Add(new TNamed("ChGap42", "ChGap42")); //gap case + fFC->SetName("FlowContainer"); + fFC->Initialize(oba, axisMultiplicity, 1); + delete oba; + } + + void FillFC(const GFW::CorrConfig& corconf, const double& cent, const double& rndm) + { + double dnx, val; + dnx = fGFW->Calculate(corrconfigs.at(0), 0, kTRUE).Re(); + if (dnx == 0) + return; + if (!corconf.pTDif) { + val = fGFW->Calculate(corrconfigs.at(0), 0, kFALSE).Re() / dnx; + if (TMath::Abs(val) < 1) + fFC->FillProfile(corrconfigs.at(0).Head.Data(), cent, val, 1, rndm); + return; + } + return; + } + + void process(soa::Filtered>::iterator const& collision, aod::BCsWithTimestamps const&, myTracks const& tracks) + { + auto bc = collision.bc_as(); + + if (cfgAcceptance.value.empty() == false) { + cfg.mAcceptance = ccdb->getForTimeStamp(cfgAcceptance.value, bc.timestamp()); + if (cfg.mAcceptance) + LOGF(info, "Loaded acceptance histogram from %s (%p)", cfgAcceptance.value.c_str(), (void*)cfg.mAcceptance); + else + LOGF(warning, "Could not load acceptance histogram from %s (%p)", cfgAcceptance.value.c_str(), (void*)cfg.mAcceptance); + } + + if (tracks.size() < 1) + return; + double vtxz = collision.posZ(); + registry.fill(HIST("hVtxZ"), vtxz); + + fGFW->Clear(); + const auto centrality = collision.centV0M(); + double dnx, val; + double l_Random = fRndm->Rndm(); + double weff, wacc; + for (auto track = tracks.begin(); track != tracks.end(); ++track) { + registry.fill(HIST("hPhi"), track.phi()); + registry.fill(HIST("hEta"), track.eta()); + if (cfg.mEfficiency) + weff = cfg.mEfficiency->GetBinContent(cfg.mEfficiency->FindBin(track.pt())); + else + weff = 1.0; + if (weff == 0) + continue; + weff = 1. / weff; + if (cfg.mAcceptance) + wacc = cfg.mAcceptance->GetNUA(track.phi(), track.eta(), vtxz); + else + wacc = 1; + + fGFW->Fill(track.eta(), 1, track.phi(), wacc * weff, 3); + } + for (int l_ind = 0; l_ind < corrconfigs.size(); l_ind++) { + FillFC(corrconfigs.at(l_ind), centrality, l_Random); + }; + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return WorkflowSpec{ + adaptAnalysisTask(cfgc), + }; +} \ No newline at end of file diff --git a/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/FlowContainer.h b/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/FlowContainer.h new file mode 100644 index 0000000000000..634d82c916b34 --- /dev/null +++ b/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/FlowContainer.h @@ -0,0 +1,161 @@ +/* +Author: Vytautas Vislavicius +Extention of Generic Flow (https://arxiv.org/abs/1312.3572) +*/ +#ifndef FLOWCONTAINER__H +#define FLOWCONTAINER__H +#include "TH3F.h" +#include "TProfile2D.h" +#include "TProfile.h" +#include "TNamed.h" +#include "TH1.h" +#include "TMath.h" +#include "TFile.h" +#include "TAxis.h" +#include "TString.h" +#include "TObjArray.h" +#include "GenericFramework/ProfileSubset.h" +#include "Framework/HistogramRegistry.h" +#include "TRandom.h" +#include "TString.h" +#include "TCollection.h" +#include "TAxis.h" + +class FlowContainer : public TNamed +{ + public: + FlowContainer(); + FlowContainer(const char* name); + ~FlowContainer(); + enum StatisticsType { kSingleSample, + kJackKnife, + kBootstrap }; + void Initialize(TObjArray* inputList, const o2::framework::AxisSpec axis, Int_t nRandomized = 0); + void Initialize(TObjArray* inputList, Int_t nMultiBins, Double_t MultiMin, Double_t MultiMax, Int_t nRandomized = 0); + Bool_t CreateBinsFromAxis(TAxis* inax); + void SetXAxis(TAxis* inax); + void SetXAxis(); + void RebinMulti(Int_t rN) + { + if (fProf) + fProf->RebinX(rN); + }; + Int_t GetNMultiBins() { return fProf->GetNbinsX(); }; + Double_t GetMultiAtBin(Int_t bin) { return fProf->GetXaxis()->GetBinCenter(bin); }; + Int_t FillProfile(const char* hname, Double_t multi, Double_t y, Double_t w, Double_t rn); + TProfile2D* GetProfile() { return fProf; }; + void OverrideProfileErrors(TProfile2D* inpf); + void ReadAndMerge(const char* infile); + void PickAndMerge(TFile* tfi); + Bool_t OverrideBinsWithZero(Int_t xb1, Int_t yb1, Int_t xb2, Int_t yb2); + Bool_t OverrideMainWithSub(Int_t subind, Bool_t ExcludeChosen); + Bool_t RandomizeProfile(Int_t nSubsets = 0); + Bool_t CreateStatisticsProfile(StatisticsType StatType, Int_t arg); + TObjArray* GetSubProfiles() { return fProfRand; }; + Long64_t Merge(TCollection* collist); + void SetIDName(TString newname); //! do not store + void SetPtRebin(Int_t newval) { fPtRebin = newval; }; + void SetPtRebin(Int_t nbins, Double_t* binedges); + void SetMultiRebin(Int_t nbins, Double_t* binedges); + Double_t* GetMultiRebin(Int_t& nBins); + void SetPropagateErrors(Bool_t newval) { fPropagateErrors = newval; }; + TProfile* GetCorrXXVsMulti(const char* order, Int_t l_pti = 0); //pti = 0 for pt-integrated + TProfile* GetCorrXXVsPt(const char* order, Double_t lminmulti = -1, Double_t lmaxmulti = -1); //0 for multi. integrated + TH1D* GetHistCorrXXVsMulti(const char* order, Int_t l_pti = 0); //pti = 0 for pt-integrated + TH1D* GetHistCorrXXVsPt(const char* order, Double_t lminmulti = -1, Double_t lmaxmulti = -1); //0 for multi. integrated + + TH1D* GetVN2VsMulti(Int_t n = 2, Int_t l_pta = 0) { return GetVN2VsX(n, kFALSE, l_pta); }; + TH1D* GetVN2VsPt(Int_t n = 2, Double_t min = -1, Double_t max = -1) { return GetVN2VsX(n, kTRUE, min, max); }; + TH1D* GetCN4VsMulti(Int_t n = 2, Int_t pti = 0) { return GetCN4VsX(n, kFALSE, pti); }; + TH1D* GetCN4VsPt(Int_t n = 2, Double_t min = -1, Double_t max = -1) { return GetCN4VsX(n, kTRUE, min, max); }; + + TH1D* GetVN4VsMulti(Int_t n = 2, Int_t pti = 0) { return GetVN4VsX(n, kFALSE, pti); }; + TH1D* GetVN4VsPt(Int_t n = 2, Double_t min = -1, Double_t max = -1) { return GetVN4VsX(n, kTRUE, min, max); }; + + TH1D* GetVN6VsMulti(Int_t n = 2, Int_t pti = 0) { return GetVN6VsX(n, kFALSE, pti); }; + TH1D* GetVN6VsPt(Int_t n = 2, Double_t min = -1, Double_t max = -1) { return GetVN6VsX(n, kTRUE, min, max); }; + + TH1D* GetVN8VsMulti(Int_t n = 2, Int_t pti = 0) { return GetVN8VsX(n, kFALSE, pti); }; + TH1D* GetVN8VsPt(Int_t n = 2, Double_t min = -1, Double_t max = -1) { return GetVN8VsX(n, kTRUE, min, max); }; + + TH1D* GetCNN(Int_t n = 2, Int_t c = 2, Bool_t onPt = kTRUE, Double_t arg1 = -1, Double_t arg2 = -1); + TH1D* GetVNN(Int_t n = 2, Int_t c = 2, Bool_t onPt = kTRUE, Double_t arg1 = -1, Double_t arg2 = -1); + + // private: + + Double_t CN2Value(Double_t cor2); //This is redundant, but adding for completeness + Double_t CN2Error(Double_t cor2e); //Also redundant + Double_t VN2Value(Double_t cor2); + Double_t VN2Error(Double_t cor2, Double_t cor2e); + Double_t VDN2Value(Double_t cor2d, Double_t cor2); + Double_t VDN2Error(Double_t cor2d, Double_t cor2de, Double_t cor2, Double_t cor2e); + + Double_t CN4Value(Double_t cor4, Double_t cor2); + Double_t CN4Error(Double_t cor4e, Double_t cor2, Double_t cor2e); + Double_t DN4Value(Double_t cor4d, Double_t cor2d, Double_t cor2); + Double_t DN4Error(Double_t cor4de, Double_t cor2d, Double_t cor2de, Double_t cor2, Double_t cor2e); + Double_t VN4Value(Double_t c4); + Double_t VN4Error(Double_t c4, Double_t c4e); + Double_t VDN4Value(Double_t d4, Double_t c4); + Double_t VDN4Error(Double_t d4, Double_t d4e, Double_t c4, Double_t c4e); + + Double_t CN6Value(Double_t cor6, Double_t cor4, Double_t cor2); + Double_t CN6Error(Double_t cor6e, Double_t cor4, Double_t cor4e, Double_t cor2, Double_t cor2e); + + Double_t DN6Value(Double_t cor6d, Double_t cor4d, Double_t cor2d, Double_t cor4, Double_t cor2); + Double_t DN6Error(Double_t d6e, Double_t d4, Double_t d4e, Double_t d2, + Double_t d2e, Double_t c4, Double_t c4e, Double_t c2, + Double_t c2e); + Double_t VN6Value(Double_t c6); + Double_t VN6Error(Double_t c6, Double_t c6e); + Double_t VDN6Value(Double_t d6, Double_t c6); + Double_t VDN6Error(Double_t d6, Double_t d6e, Double_t c6, Double_t c6e); + + Double_t CN8Value(Double_t cor8, Double_t cor6, Double_t cor4, Double_t cor2); + Double_t CN8Error(Double_t cor8e, Double_t cor6, Double_t cor6e, + Double_t cor4, Double_t cor4e, Double_t cor2, Double_t cor2e); + Double_t DN8Value(Double_t cor8d, Double_t cor6d, Double_t cor4d, Double_t cor2d, Double_t cor6, Double_t cor4, Double_t cor2); + Double_t DN8Error(Double_t d8e, Double_t d6, Double_t d6e, Double_t d4, + Double_t d4e, Double_t d2, Double_t d2e, Double_t c6, + Double_t c6e, Double_t c4, Double_t c4e, Double_t c2, + Double_t c2e); + Double_t VN8Value(Double_t c8); + Double_t VN8Error(Double_t c8, Double_t c8e); + Double_t VDN8Value(Double_t d8, Double_t c8); + Double_t VDN8Error(Double_t d8, Double_t d8e, Double_t c8, Double_t c8e); + + TH1D* GetCN2VsX(Int_t n = 2, Bool_t onPt = kTRUE, Double_t larg1 = -1, Double_t larg2 = -1); //This one is redundant + TH1D* GetVN2VsX(Int_t n = 2, Bool_t onPt = kTRUE, Double_t larg1 = -1, Double_t larg2 = -1); + TH1D* GetCN4VsX(Int_t n = 2, Bool_t onPt = kTRUE, Double_t larg1 = -1, Double_t larg2 = -1); + TH1D* GetVN4VsX(Int_t n = 2, Bool_t onPt = kTRUE, Double_t larg1 = -1, Double_t larg2 = -1); + TH1D* GetCN6VsX(Int_t n = 2, Bool_t onPt = kTRUE, Double_t larg1 = -1, Double_t larg2 = -1); + TH1D* GetVN6VsX(Int_t n = 2, Bool_t onPt = kTRUE, Double_t larg1 = -1, Double_t larg2 = -1); + TH1D* GetCN8VsX(Int_t n = 2, Bool_t onPt = kTRUE, Double_t larg1 = -1, Double_t larg2 = -1); + TH1D* GetVN8VsX(Int_t n = 2, Bool_t onPt = kTRUE, Double_t larg1 = -1, Double_t larg2 = -1); + + TH1D* GetVN2(TH1D* cn2); + TH1D* GetVN4(TH1D* inh); + TH1D* GetVN6(TH1D* inh); + TH1D* GetVN8(TH1D* inh); + TH1D* GetCN2(TH1D* corrN2); + TH1D* GetCN4(TH1D* corrN4, TH1D* corrN2); + TH1D* GetCN6(TH1D* corrN6, TH1D* corrN4, TH1D* corrN2); + TH1D* GetCN8(TH1D* corrN8, TH1D* corrN6, TH1D* corrN4, TH1D* corrN2); + TH1D* ProfToHist(TProfile* inpf); + TProfile2D* fProf; + TObjArray* fProfRand; + Int_t fNRandom; + TString fIDName; + Int_t fPtRebin; //! do not store + Double_t* fPtRebinEdges; //! do not store + Int_t fMultiRebin; //! do not store + Double_t* fMultiRebinEdges; //! do not store + TAxis* fXAxis; + Int_t fNbinsPt; //! Do not store; stored in the fXAxis + Double_t* fbinsPt; //! Do not store; stored in fXAxis + Bool_t fPropagateErrors; //! do not store + TProfile* GetRefFlowProfile(const char* order, Double_t m1 = -1, Double_t m2 = -1); + ClassDef(FlowContainer, 2); +}; + +#endif \ No newline at end of file diff --git a/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/GFW.h b/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/GFW.h new file mode 100644 index 0000000000000..0ae090bbc4b77 --- /dev/null +++ b/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/GFW.h @@ -0,0 +1,87 @@ +/* +Author: Vytautas Vislavicius +Extention of Generic Flow (https://arxiv.org/abs/1312.3572) +*/ +#ifndef GFW__H +#define GFW__H +#include "GenericFramework/GFWCumulant.h" +#include +#include +#include +#include "TString.h" +#include "TObjArray.h" +using std::vector; + +class GFW +{ + public: + struct Region { + Int_t Nhar, Npar, NpT; + vector NparVec; + Double_t EtaMin = -999; + Double_t EtaMax = -999; + Int_t BitMask = 1; + TString rName = ""; + bool operator<(const Region& a) const + { + return EtaMin < a.EtaMin; + }; + Region operator=(const Region& a) + { + Nhar = a.Nhar; + Npar = a.Npar; + NparVec = a.NparVec; + NpT = a.NpT; + EtaMin = a.EtaMin; + EtaMax = a.EtaMax; + rName = a.rName; + BitMask = a.BitMask; + return *this; + }; + void PrintStructure() { printf("%s: eta [%f.. %f].", rName.Data(), EtaMin, EtaMax); }; + }; + struct CorrConfig { + vector> Regs{}; + vector> Hars{}; + vector Overlap; + Bool_t pTDif = kFALSE; + TString Head = ""; + }; + GFW(); + ~GFW(); + vector fRegions; + vector fCumulants; + vector fEmptyInt; + void AddRegion(TString refName, Int_t lNhar, Int_t lNpar, Double_t lEtaMin, Double_t lEtaMax, Int_t lNpT = 1, Int_t BitMask = 1); + void AddRegion(TString refName, Int_t lNhar, Int_t* lNparVec, Double_t lEtaMin, Double_t lEtaMax, Int_t lNpT = 1, Int_t BitMask = 1); + Int_t CreateRegions(); + void Fill(Double_t eta, Int_t ptin, Double_t phi, Double_t weight, Int_t mask, Double_t secondWeight = -1); + void Clear(); // { for(auto ptr = fCumulants.begin(); ptr!=fCumulants.end(); ++ptr) ptr->ResetQs(); }; + GFWCumulant GetCumulant(Int_t index) { return fCumulants.at(index); }; + TComplex Calculate(TString config, Bool_t SetHarmsToZero = kFALSE); + CorrConfig GetCorrelatorConfig(TString config, TString head = "", Bool_t ptdif = kFALSE); + TComplex Calculate(CorrConfig corconf, Int_t ptbin, Bool_t SetHarmsToZero, Bool_t DisableOverlap = kFALSE); + + private: + Bool_t fInitialized; + void SplitRegions(); + GFWCumulant fEmptyCumulant; + TComplex TwoRec(Int_t n1, Int_t n2, Int_t p1, Int_t p2, Int_t ptbin, GFWCumulant*, GFWCumulant*, GFWCumulant*); + TComplex RecursiveCorr(GFWCumulant* qpoi, GFWCumulant* qref, GFWCumulant* qol, Int_t ptbin, vector& hars, vector& pows); //POI, Ref. flow, overlapping region + TComplex RecursiveCorr(GFWCumulant* qpoi, GFWCumulant* qref, GFWCumulant* qol, Int_t ptbin, vector& hars); //POI, Ref. flow, overlapping region + //Deprecated and not used (for now): + void AddRegion(Region inreg) { fRegions.push_back(inreg); }; + Region GetRegion(Int_t index) { return fRegions.at(index); }; + Int_t FindRegionByName(TString refName); + vector fCalculatedNames; + vector fCalculatedQs; + Int_t FindCalculated(TString identifier); + //Calculateing functions: + TComplex Calculate(Int_t poi, Int_t ref, vector hars, Int_t ptbin = 0); //For differential, need POI and reference + TComplex Calculate(Int_t poi, vector hars); //For integrated case + //Process one string (= one region) + TComplex CalculateSingle(TString config); + + Bool_t SetHarmonicsToZero(TString& instr); +}; +#endif \ No newline at end of file diff --git a/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/GFWCumulant.h b/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/GFWCumulant.h new file mode 100644 index 0000000000000..c95bb131e8e9d --- /dev/null +++ b/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/GFWCumulant.h @@ -0,0 +1,53 @@ +/* +Author: Vytautas Vislavicius +Extention of Generic Flow (https://arxiv.org/abs/1312.3572) +*/ +#ifndef GFWCUMULANT__H +#define GFWCUMULANT__H +#include "TComplex.h" +#include "TNamed.h" +#include "TMath.h" +#include "TAxis.h" +using std::vector; +class GFWCumulant +{ + public: + GFWCumulant(); + ~GFWCumulant(); + void ResetQs(); + void FillArray(Double_t eta, Int_t ptin, Double_t phi, Double_t weight = 1, Double_t SecondWeight = -1); + enum UsedFlags_t { kBlank = 0, + kFull = 1, + kPt = 2 }; + void SetType(UInt_t infl) + { + DestroyComplexVectorArray(); + fUsed = infl; + }; + void Inc() { fNEntries++; }; + Int_t GetN() { return fNEntries; }; + // protected: + TComplex*** fQvector; + UInt_t fUsed; + Int_t fNEntries; + //Q-vectors. Could be done recursively, but maybe defining each one of them explicitly is easier to read + TComplex Vec(Int_t, Int_t, Int_t ptbin = 0); //envelope class to summarize pt-dif. Q-vec getter + Int_t fN; //! Harmonics + Int_t fPow; //! Power + vector fPowVec; //! Powers array + Int_t fPt; //!fPt bins + Bool_t* fFilledPts; + Bool_t fInitialized; //Arrays are initialized + void CreateComplexVectorArray(Int_t N = 1, Int_t P = 1, Int_t Pt = 1); + void CreateComplexVectorArrayVarPower(Int_t N = 1, vector Pvec = {1}, Int_t Pt = 1); + Int_t PW(Int_t ind) { return fPowVec.at(ind); }; //No checks to speed up, be carefull!!! + void DestroyComplexVectorArray(); + Bool_t IsPtBinFilled(Int_t ptb) + { + if (!fFilledPts) + return kFALSE; + return fFilledPts[ptb]; + }; +}; + +#endif \ No newline at end of file diff --git a/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/GFWWeights.h b/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/GFWWeights.h new file mode 100644 index 0000000000000..ba56cc09ec4a9 --- /dev/null +++ b/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/GFWWeights.h @@ -0,0 +1,70 @@ +/* +Author: Vytautas Vislavicius +Extention of Generic Flow (https://arxiv.org/abs/1312.3572) +*/ +#ifndef GFWWeights__H +#define GFWWeights__H +#include "TObjArray.h" +#include "TNamed.h" +#include "TH3D.h" +#include "TH2D.h" +#include "TH1D.h" +#include "TFile.h" +#include "TCollection.h" +#include "TString.h" + +class GFWWeights : public TNamed +{ + public: + GFWWeights(); + ~GFWWeights(); + void Init(Bool_t AddData = kTRUE, Bool_t AddM = kTRUE); + void Fill(Double_t phi, Double_t eta, Double_t vz, Double_t pt, Double_t cent, Int_t htype, Double_t weight = 1); //htype: 0 for data, 1 for mc rec, 2 for mc gen + Double_t GetWeight(Double_t phi, Double_t eta, Double_t vz, Double_t pt, Double_t cent, Int_t htype); //htype: 0 for data, 1 for mc rec, 2 for mc gen + Double_t GetNUA(Double_t phi, Double_t eta, Double_t vz); //This just fetches correction from integrated NUA, should speed up + Double_t GetNUE(Double_t pt, Double_t eta, Double_t vz); //fetches weight from fEffInt + Bool_t IsDataFilled() { return fDataFilled; }; + Bool_t IsMCFilled() { return fMCFilled; }; + Double_t FindMax(TH3D* inh, Int_t& ix, Int_t& iy, Int_t& iz); + void MCToEfficiency(); + TObjArray* GetRecArray() { return fW_mcrec; }; + TObjArray* GetGenArray() { return fW_mcgen; }; + TObjArray* GetDataArray() { return fW_data; }; + void CreateNUA(Bool_t IntegrateOverCentAndPt = kTRUE); + void CreateNUE(Bool_t IntegrateOverCentrality = kTRUE); + TH1D* GetIntegratedEfficiencyHist(); + Bool_t CalculateIntegratedEff(); + Double_t GetIntegratedEfficiency(Double_t pt); + void SetDataFilled(Bool_t newval) { fDataFilled = newval; }; + void SetMCFilled(Bool_t newval) { fMCFilled = newval; }; + void ReadAndMerge(TString filelinks, TString listName = "OutputList", Bool_t addData = kTRUE, Bool_t addRec = kTRUE, Bool_t addGen = kTRUE); + void SetPtBins(Int_t Nbins, Double_t* bins); + Long64_t Merge(TCollection* collist); + void RebinNUA(Int_t nX = 1, Int_t nY = 2, Int_t nZ = 5); + void OverwriteNUA(); + TH1D* GetdNdPhi(); + TH1D* GetEfficiency(Double_t etamin, Double_t etamax, Double_t vzmin, Double_t vzmax); + + private: + Bool_t fDataFilled; + Bool_t fMCFilled; + TObjArray* fW_data; + TObjArray* fW_mcrec; + TObjArray* fW_mcgen; + TH3D* fEffInt; //! + TH1D* fIntEff; //! + TH3D* fAccInt; //! + Int_t fNbinsPt; //! do not store + Double_t* fbinsPt; //! do not store + void AddArray(TObjArray* targ, TObjArray* sour); + const char* GetBinName(Double_t ptv, Double_t v0mv, const char* pf = "") + { + Int_t ptind = 0; //GetPtBin(ptv); + Int_t v0mind = 0; //GetV0MBin(v0mv); + return Form("Bin%s_weights%i_%i", pf, ptind, v0mind); + }; + + ClassDef(GFWWeights, 1); +}; + +#endif \ No newline at end of file diff --git a/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/ProfileSubset.h b/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/ProfileSubset.h new file mode 100644 index 0000000000000..c1a39b468b2b3 --- /dev/null +++ b/Analysis/Tasks/PWGCF/GenericFramework/include/GenericFramework/ProfileSubset.h @@ -0,0 +1,24 @@ +/* +Author: Vytautas Vislavicius +Extention of Generic Flow (https://arxiv.org/abs/1312.3572) +*/ +#ifndef ProfileSubset__H +#define ProfileSubset__H +//Helper function to select a subrange of a TProfile +#include "TProfile.h" +#include "TProfile2D.h" +#include "TError.h" + +class ProfileSubset : public TProfile2D +{ + public: + ProfileSubset(TProfile2D& inpf) : TProfile2D(inpf){}; + ~ProfileSubset(){}; + TProfile* GetSubset(Bool_t onx, const char* name, Int_t fb, Int_t lb, Int_t l_nbins = 0, Double_t* l_binarray = 0); + void OverrideBinContent(Double_t x, Double_t y, Double_t x2, Double_t y2, Double_t val); + void OverrideBinContent(Double_t x, Double_t y, Double_t x2, Double_t y2, TProfile2D* sourceProf); + Bool_t OverrideBinsWithZero(Int_t xb1, Int_t yb1, Int_t xb2, Int_t yb2); + + ClassDef(ProfileSubset, 2); +}; +#endif \ No newline at end of file diff --git a/Analysis/Tasks/PWGCF/GenericFramework/src/FlowContainer.cxx b/Analysis/Tasks/PWGCF/GenericFramework/src/FlowContainer.cxx new file mode 100644 index 0000000000000..4331552847508 --- /dev/null +++ b/Analysis/Tasks/PWGCF/GenericFramework/src/FlowContainer.cxx @@ -0,0 +1,1218 @@ +/* +Author: Vytautas Vislavicius +Extention of Generic Flow (https://arxiv.org/abs/1312.3572) +*/ +#include "GenericFramework/FlowContainer.h" + +ClassImp(FlowContainer); + +FlowContainer::FlowContainer() : TNamed("", ""), + fProf(0), + fProfRand(0), + fNRandom(0), + fIDName("MidV"), + fPtRebin(1), + fPtRebinEdges(0), + fMultiRebin(0), + fMultiRebinEdges(0), + fXAxis(0), + fNbinsPt(0), + fbinsPt(0), + fPropagateErrors(kFALSE){}; +FlowContainer::FlowContainer(const char* name) : TNamed(name, name), + fProf(0), + fProfRand(0), + fNRandom(0), + fIDName("MidV"), + fPtRebin(1), + fPtRebinEdges(0), + fMultiRebin(0), + fMultiRebinEdges(0), + fXAxis(0), + fNbinsPt(0), + fbinsPt(0), + fPropagateErrors(kFALSE){}; +FlowContainer::~FlowContainer() +{ + delete fProf; + delete fProfRand; +}; +void FlowContainer::Initialize(TObjArray* inputList, const o2::framework::AxisSpec axis, Int_t nRandom) +{ + std::vector multiBins = axis.binEdges; + int nMultiBins = axis.nBins.value_or(0); + if (nMultiBins == 0) + nMultiBins = multiBins.size(); + if (nMultiBins == 0) { + printf("Multiplicity axis does not exist"); + return; + } + if (!inputList) { + printf("Input list not specified\n"); + return; + }; + if (inputList->GetEntries() < 1) { + printf("Input list empty!\n"); + return; + }; + fProf = new TProfile2D(Form("%s_CorrProfile", this->GetName()), "CorrProfile", nMultiBins, &multiBins[0], inputList->GetEntries(), 0.5, inputList->GetEntries() + 0.5); + for (Int_t i = 0; i < inputList->GetEntries(); i++) + fProf->GetYaxis()->SetBinLabel(i + 1, inputList->At(i)->GetName()); + fProf->Sumw2(); + if (nRandom) { + fNRandom = nRandom; + fProfRand = new TObjArray(); + fProfRand->SetOwner(kTRUE); + for (Int_t i = 0; i < nRandom; i++) { + fProfRand->Add((TProfile2D*)fProf->Clone(Form("%s_Rand_%i", fProf->GetName(), i))); + ((TProfile2D*)fProfRand->At(i))->Sumw2(); + }; + }; +}; +void FlowContainer::Initialize(TObjArray* inputList, Int_t nMultiBins, Double_t MultiMin, Double_t MultiMax, Int_t nRandom) +{ + if (!inputList) { + printf("Input list not specified\n"); + return; + }; + if (inputList->GetEntries() < 1) { + printf("Input list empty!\n"); + return; + }; + fProf = new TProfile2D(Form("%s_CorrProfile", this->GetName()), "CorrProfile", nMultiBins, MultiMin, MultiMax, inputList->GetEntries(), 0.5, inputList->GetEntries() + 0.5); + fProf->SetDirectory(0); + fProf->Sumw2(); + for (Int_t i = 0; i < inputList->GetEntries(); i++) + fProf->GetYaxis()->SetBinLabel(i + 1, inputList->At(i)->GetName()); + if (nRandom) { + fNRandom = nRandom; + fProfRand = new TObjArray(); + fProfRand->SetOwner(kTRUE); + for (Int_t i = 0; i < nRandom; i++) { + fProfRand->Add((TProfile2D*)fProf->Clone(Form("%s_Rand_%i", fProf->GetName(), i))); + ((TProfile2D*)fProfRand->At(i))->Sumw2(); + }; + }; +}; +Bool_t FlowContainer::CreateBinsFromAxis(TAxis* inax) +{ + if (!inax) + return kFALSE; + fNbinsPt = inax->GetNbins(); + fbinsPt = new Double_t[fNbinsPt + 1]; + inax->GetLowEdge(fbinsPt); + fbinsPt[fNbinsPt] = inax->GetBinUpEdge(fNbinsPt); + return kTRUE; +} +void FlowContainer::SetXAxis(TAxis* inax) +{ + fXAxis = (TAxis*)inax->Clone("pTAxis"); + Bool_t success = CreateBinsFromAxis(fXAxis); + if (!success) + printf("Something went wrong setting the x axis!\n"); +} +void FlowContainer::SetXAxis() +{ + if (!CreateBinsFromAxis(fXAxis)) { //Legacy; if fXAxis not defined, then setup default one + const Int_t NbinsPtForV2 = 24; + Double_t binsPtForV2[NbinsPtForV2 + 1] = { + 0.2, 0.4, 0.6, 0.8, 1.0, + 1.2, 1.4, 1.6, 1.8, 2.0, + 2.2, 2.4, 2.6, 3.0, 3.4, + 3.8, 4.2, 4.6, 5.2, 5.8, + 6.6, 8.0, 12.0, 16.0, 20.0}; + TAxis* tempax = new TAxis(NbinsPtForV2, binsPtForV2); + SetXAxis(tempax); + delete tempax; + } +} +Int_t FlowContainer::FillProfile(const char* hname, Double_t multi, Double_t corr, Double_t w, Double_t rn) +{ + if (!fProf) + return -1; + Int_t yin = fProf->GetYaxis()->FindBin(hname); + if (!yin) { + printf("Could not find bin %s\n", hname); + return -1; + }; + fProf->Fill(multi, yin, corr, w); + if (fNRandom) { + Double_t rnind = rn * fNRandom; + ((TProfile2D*)fProfRand->At((Int_t)rnind))->Fill(multi, yin, corr, w); + }; + return 0; +}; +void FlowContainer::OverrideProfileErrors(TProfile2D* inpf) +{ + Int_t nBinsX = fProf->GetNbinsX(); + Int_t nBinsY = fProf->GetNbinsY(); + if ((inpf->GetNbinsX() != nBinsX) || (inpf->GetNbinsY() != nBinsY)) { + printf("Number of bins in two profiles do not match, not doing anything\n"); + return; + }; + if (!inpf->GetBinSumw2()->fArray) { + printf("Input profile has no BinSumw2()! Returning\n"); + return; + } + if (!fProf->GetBinSumw2()->fArray) + fProf->Sumw2(); + Double_t* sumw2Prof = fProf->GetSumw2()->fArray; + Double_t* sumw2Targ = inpf->GetSumw2()->fArray; + Double_t* binsw2Prof = fProf->GetBinSumw2()->fArray; + Double_t* binsw2Targ = inpf->GetBinSumw2()->fArray; + Double_t* farrProf = fProf->fArray; + Double_t* farrTarg = inpf->fArray; + for (Int_t ix = 1; ix <= nBinsX; ix++) { + Double_t xval = fProf->GetXaxis()->GetBinCenter(ix); + printf("Processing x-bin %i\n", ix); + for (Int_t iy = 1; iy <= nBinsY; iy++) { + //printf("Processing bin [%i, %i] out of [%i, %i]\n",ix,iy,nBinsX, nBinsY); + Double_t yval = fProf->GetYaxis()->GetBinCenter(iy); + Int_t binno = fProf->FindBin(xval, yval); + Double_t h = fProf->GetBinContent(binno); + Double_t lEnt = inpf->GetBinEntries(binno); + fProf->SetBinEntries(binno, lEnt); + sumw2Prof[binno] = sumw2Targ[binno]; + binsw2Prof[binno] = binsw2Targ[binno]; + farrProf[binno] = h * lEnt; + /*fProf->GetBinSumw2()->fArray[binno] = inpf->GetBinSumw2()->fArray[binno]; + fProf->SetBinEntries(binno,inpf->GetBinEntries(binno)); + fProf->GetSumw2()->fArray[binno] = inpf->GetSumw2()->fArray[binno]; + fProf->SetBinContent(binno,h*fProf->GetBinEntries(binno));*/ + } + } +} +Long64_t FlowContainer::Merge(TCollection* collist) +{ + Long64_t nmerged = 0; + FlowContainer* l_FC = 0; + TIter all_FC(collist); + //TProfile2D *spro = lfc->GetProfile(); + while (l_FC = ((FlowContainer*)all_FC())) { + TProfile2D* tpro = GetProfile(); + TProfile2D* spro = l_FC->GetProfile(); + if (!tpro) { + fProf = (TProfile2D*)spro->Clone(spro->GetName()); + fProf->SetDirectory(0); + } else + tpro->Add(spro); + nmerged++; + TObjArray* tarr = l_FC->GetSubProfiles(); + if (!tarr) + continue; + if (!fProfRand) { + fProfRand = new TObjArray(); + fProfRand->SetOwner(kTRUE); + }; + for (Int_t i = 0; i < tarr->GetEntries(); i++) { + if (!(fProfRand->FindObject(tarr->At(i)->GetName()))) { + fProfRand->Add((TProfile2D*)tarr->At(i)->Clone(tarr->At(i)->GetName())); + ((TProfile2D*)fProfRand->At(fProfRand->GetEntries() - 1))->SetDirectory(0); + } else { + ((TProfile2D*)fProfRand->FindObject(tarr->At(i)->GetName()))->Add((TProfile2D*)tarr->At(i)); + }; + }; + }; + return nmerged; +}; +void FlowContainer::ReadAndMerge(const char* filelist) +{ + FILE* flist = fopen(filelist, "r"); + char str[150]; + Int_t nFiles = 0; + while (fscanf(flist, "%s\n", str) == 1) + nFiles++; + rewind(flist); + if (nFiles == 0) { + printf("No files to read!\n"); + return; + }; + for (Int_t i = 0; i < nFiles; i++) { + Int_t trash = fscanf(flist, "%s\n", str); + TFile* tf = new TFile(str, "READ"); + if (tf->IsZombie()) { + printf("Could not open file %s!\n", str); + tf->Close(); + continue; + }; + PickAndMerge(tf); + tf->Close(); + }; +}; +void FlowContainer::PickAndMerge(TFile* tfi) +{ + FlowContainer* lfc = (FlowContainer*)tfi->Get(this->GetName()); + if (!lfc) { + printf("Could not pick up the %s from %s\n", this->GetName(), tfi->GetName()); + return; + }; + TProfile2D* spro = lfc->GetProfile(); + TProfile2D* tpro = GetProfile(); + if (!tpro) { + fProf = (TProfile2D*)spro->Clone(spro->GetName()); + fProf->SetDirectory(0); + } else + tpro->Add(spro); + TObjArray* tarr = lfc->GetSubProfiles(); + if (!tarr) { + //printf("Target %s does not have subprofiles!\n",lfc->GetName()); + return; + }; + if (!fProfRand) { + fProfRand = new TObjArray(); + fProfRand->SetOwner(kTRUE); + }; + for (Int_t i = 0; i < tarr->GetEntries(); i++) { + if (!(fProfRand->FindObject(tarr->At(i)->GetName()))) { + //printf("Adding %s (%i)\n",tarr->At(i)->GetName(),i); + fProfRand->Add((TProfile2D*)tarr->At(i)->Clone(tarr->At(i)->GetName())); + ((TProfile2D*)fProfRand->At(fProfRand->GetEntries() - 1))->SetDirectory(0); + } else { + ((TProfile2D*)fProfRand->FindObject(tarr->At(i)->GetName()))->Add((TProfile2D*)tarr->At(i)); + }; + }; + //printf("After merge: %i in target, %i in source\n",fProfRand->GetEntries(),tarr->GetEntries()); +}; +Bool_t FlowContainer::OverrideBinsWithZero(Int_t xb1, Int_t yb1, Int_t xb2, Int_t yb2) +{ + ProfileSubset* t_apf = new ProfileSubset(*fProf); + if (!t_apf->OverrideBinsWithZero(xb1, yb1, xb2, yb2)) { + delete t_apf; + return kFALSE; + }; + delete fProf; + fProf = (TProfile2D*)t_apf; + return kTRUE; +} +Bool_t FlowContainer::OverrideMainWithSub(Int_t ind, Bool_t ExcludeChosen) +{ + if (!fProfRand) { + printf("Cannot override main profile with a randomized one. Random profile array does not exist.\n"); + return kFALSE; + }; + if (!ExcludeChosen) { + TProfile2D* tarprof = (TProfile2D*)fProfRand->At(ind); + if (!tarprof) { + printf("Target random histogram does not exist.\n"); + return kFALSE; + }; + TString ts(fProf->GetName()); + delete fProf; + fProf = (TProfile2D*)tarprof->Clone(ts.Data()); + return kTRUE; + } else { + TString ts(fProf->GetName()); + delete fProf; + fProf = 0; + for (Int_t i = 0; i < fProfRand->GetEntries(); i++) { + if (i == ind) + continue; + TProfile2D* tarprof = (TProfile2D*)fProfRand->At(i); + if (!fProf) + fProf = (TProfile2D*)tarprof->Clone(ts.Data()); + else + fProf->Add(tarprof); + }; + return kTRUE; + }; +}; +Bool_t FlowContainer::RandomizeProfile(Int_t nSubsets) +{ + if (!fProfRand) { + printf("Cannot randomize profile, random array does not exist.\n"); + return kFALSE; + }; + Int_t l_Subsets = nSubsets ? nSubsets : fProfRand->GetEntries(); + TRandom* rndm = new TRandom(0); + for (Int_t i = 0; i < l_Subsets; i++) { + Int_t rInd = TMath::FloorNint(rndm->Rndm() * fProfRand->GetEntries()); + if (!i) { + TString ts(fProf->GetName()); + delete fProf; + fProf = (TProfile2D*)fProfRand->At(rInd)->Clone(ts.Data()); + } else + fProf->Add((TProfile2D*)fProfRand->At(rInd)); + } + return kTRUE; +} +Bool_t FlowContainer::CreateStatisticsProfile(StatisticsType StatType, Int_t arg) +{ + switch (StatType) { + case kSingleSample: + //printf("Called kSingleSample\n"); + return OverrideMainWithSub(arg, kFALSE); + break; //Just dummy + case kJackKnife: + //printf("Called JackKnife\n"); + return OverrideMainWithSub(arg, kTRUE); + break; //Just dummy + case kBootstrap: + //printf("Called proper bootstrap\n"); + return RandomizeProfile(arg); + break; //Just dummy + default: + return kFALSE; + break; //Just dummy + }; +} +void FlowContainer::SetIDName(TString newname) +{ + fIDName = newname; +}; +TProfile* FlowContainer::GetCorrXXVsMulti(const char* order, Int_t l_pti) +{ + TProfile* retSubset = 0; + TString l_name(""); + Ssiz_t l_pos = 0; + while (fIDName.Tokenize(l_name, l_pos)) { + const char* ptpf = l_pti > 0 ? Form("_pt_%i", l_pti) : ""; + const char* ybinlab = Form("%s%s%s", l_name.Data(), order, ptpf); + Int_t ybinno = fProf->GetYaxis()->FindBin(ybinlab); + if (ybinno < 0) { + printf("Could not find %s!\n", ybinlab); + return 0; + }; + TProfile* rethist = (TProfile*)fProf->ProfileX("temp_prof", ybinno, ybinno); + rethist->SetTitle(Form(";multi.;#LT#LT%s#GT#GT", order)); + if (!retSubset) { + retSubset = (TProfile*)rethist->Clone(Form("corr_%s", order)); + } else { + retSubset->Add(rethist); + }; + delete rethist; + }; + if (fMultiRebin > 0) { //If needed, rebin multiplicity + TString temp_name(retSubset->GetName()); + TProfile* tempprof = (TProfile*)retSubset->Clone("tempProfile"); + delete retSubset; + retSubset = (TProfile*)tempprof->Rebin(fMultiRebin, temp_name.Data(), fMultiRebinEdges); + delete tempprof; + } + return retSubset; +}; +TProfile* FlowContainer::GetCorrXXVsPt(const char* order, Double_t lminmulti, Double_t lmaxmulti) +{ + Int_t minm = 1; + Int_t maxm = fProf->GetXaxis()->GetNbins(); + if (!fbinsPt) + SetXAxis(); + if (lminmulti > 0) { + minm = fProf->GetXaxis()->FindBin(lminmulti + 0.001); + maxm = minm; + }; + if (lmaxmulti > lminmulti) + maxm = fProf->GetXaxis()->FindBin(lmaxmulti - 0.001); + // printf("Multiplicity bins: %i to %i\n",minm,maxm); + ProfileSubset* rhProfSub = new ProfileSubset(*fProf); + TProfile* retSubset = 0; + TString l_name(""); + Ssiz_t l_pos = 0; + while (fIDName.Tokenize(l_name, l_pos)) { + //printf("working on \"%s\"\n",l_name.Data()); + TString ybl1(Form("%s%s_pt_1", l_name.Data(), order)); + TString ybl2(Form("%s%s_pt_%i", l_name.Data(), order, fNbinsPt)); + Int_t ybn1 = fProf->GetYaxis()->FindBin(ybl1.Data()); + Int_t ybn2 = fProf->GetYaxis()->FindBin(ybl2.Data()); + rhProfSub->GetYaxis()->SetRange(ybn1, ybn2); + TProfile* tempprof = rhProfSub->GetSubset(kFALSE, "tempprof", minm, maxm, fNbinsPt, fbinsPt); + if (!retSubset) { + TString profname = Form("%s_MultiB_%i_%i", order, minm, maxm); + retSubset = (TProfile*)tempprof->Clone(profname.Data()); + } else + retSubset->Add(tempprof); + delete tempprof; + }; + delete rhProfSub; + if (fPtRebinEdges) { + TString pnbu(retSubset->GetName()); + retSubset->SetName("TempName"); + TProfile* tempprof = (TProfile*)retSubset->Rebin(fPtRebin, pnbu.Data(), fPtRebinEdges); + delete retSubset; + retSubset = tempprof; + } else + retSubset->RebinX(fPtRebin); + return retSubset; +}; +TH1D* FlowContainer::ProfToHist(TProfile* inpf) +{ + Int_t nbins = inpf->GetNbinsX(); + Double_t* xbs = new Double_t[nbins + 1]; + inpf->GetLowEdge(xbs); + xbs[nbins] = xbs[nbins - 1] + inpf->GetBinWidth(nbins); + TH1D* rethist = new TH1D(Form("%s_hist", inpf->GetName()), inpf->GetTitle(), nbins, xbs); + for (Int_t i = 1; i <= rethist->GetNbinsX(); i++) { + if (inpf->GetBinContent(i) != 0) { + rethist->SetBinContent(i, inpf->GetBinContent(i)); + rethist->SetBinError(i, inpf->GetBinError(i)); //*TMath::Sqrt(inpf->GetBinEntries(i))); + }; + }; + return rethist; +}; +TH1D* FlowContainer::GetHistCorrXXVsMulti(const char* order, Int_t l_pti) +{ + TProfile* tpf = GetCorrXXVsMulti(order, l_pti); + TH1D* rethist = ProfToHist(tpf); + delete tpf; + return rethist; +}; +TH1D* FlowContainer::GetHistCorrXXVsPt(const char* order, Double_t lminmulti, Double_t lmaxmulti) +{ + TProfile* tpf = GetCorrXXVsPt(order, lminmulti, lmaxmulti); + TH1D* rethist = ProfToHist(tpf); + TProfile* refflow = GetRefFlowProfile(order, lminmulti, lmaxmulti); + refflow->RebinX(refflow->GetNbinsX()); + rethist->SetBinContent(0, refflow->GetBinContent(1)); + rethist->SetBinError(0, refflow->GetBinError(1)); + delete refflow; + delete tpf; + return rethist; +}; +TH1D* FlowContainer::GetVN2(TH1D* cn2) +{ + TH1D* rethist = (TH1D*)cn2->Clone(Form("vn2_%s", cn2->GetName())); + rethist->Reset(); + Double_t rf2 = cn2->GetBinContent(0); + Double_t rf2e = cn2->GetBinError(0); + Bool_t OnPt = (!rf2 == 0); + for (Int_t i = 1; i <= rethist->GetNbinsX(); i++) { + Double_t d2 = cn2->GetBinContent(i); + Double_t d2e = cn2->GetBinError(i); + if (d2 > 0) { + rethist->SetBinContent(i, OnPt ? VDN2Value(d2, rf2) : VN2Value(d2)); + rethist->SetBinError(i, OnPt ? VDN2Error(d2, d2e, rf2, rf2e) : VN2Error(d2, d2e)); + }; + }; + return rethist; +}; +TH1D* FlowContainer::GetCN2VsX(Int_t n, Bool_t onPt, Double_t arg1, Double_t arg2) +{ + TH1D* corrN2; + if (onPt) + corrN2 = GetHistCorrXXVsPt(Form("%i2", n), arg1, arg2); + else + corrN2 = GetHistCorrXXVsMulti(Form("%i2", n), (Int_t)arg1); + corrN2->SetName(Form("Corr_%s", corrN2->GetName())); + TH1D* rethist = GetCN2(corrN2); + TString* nam = new TString(corrN2->GetName()); + delete corrN2; + rethist->SetName(nam->Data()); + if (onPt) { + Int_t bins = fProf->GetXaxis()->FindBin(arg1); + Int_t bins2 = fProf->GetXaxis()->FindBin(arg2); + Double_t bv1 = fProf->GetXaxis()->GetBinLowEdge(bins); + Double_t bv2 = fProf->GetXaxis()->GetBinUpEdge(bins2); + rethist->SetTitle(Form("%2.0f - %4.0f;#it{p}_{T} (GeV/#it{c}); c_{%i}{2}", bv1, bv2, n)); + } else { + rethist->SetTitle(Form(";#it{N}_{tr};c_{%i}{2}", n)); + }; + return rethist; +}; + +TH1D* FlowContainer::GetVN2VsX(Int_t n, Bool_t onPt, Double_t arg1, Double_t arg2) +{ + TH1D* corrh = GetCN2VsX(n, onPt, arg1, arg2); + TString* nam = new TString(corrh->GetName()); + TH1D* rethist = GetVN2(corrh); + delete corrh; + rethist->SetName(nam->Data()); + if (onPt) { + Int_t bins = fProf->GetXaxis()->FindBin(arg1); + Int_t bins2 = fProf->GetXaxis()->FindBin(arg2); + Double_t bv1 = fProf->GetXaxis()->GetBinCenter(bins); + Double_t bv2 = fProf->GetXaxis()->GetBinCenter(bins2); + rethist->SetTitle(Form("%2.0f - %4.0f;#it{p}_{T} (GeV/#it{c}); v_{%i}{2}", bv1, bv2, n)); + } else { + rethist->SetTitle(Form(";#it{N}_{tr};v_{%i}{2}", n)); + }; + delete nam; + return rethist; +}; + +TH1D* FlowContainer::GetCN2(TH1D* corrN2) +{ + Double_t rf2 = corrN2->GetBinContent(0); + Double_t rf2e = corrN2->GetBinError(0); + Bool_t OnPt = (rf2 != 0); // This is not needed, as C2 = <2> anyway + TH1D* rethist = (TH1D*)corrN2->Clone(Form("cN2_%s", corrN2->GetName())); + rethist->Reset(); + for (Int_t i = 1; i <= rethist->GetNbinsX(); i++) { + Double_t cor2v = corrN2->GetBinContent(i); + Double_t cor2e = corrN2->GetBinError(i); + rethist->SetBinContent(i, cor2v); + rethist->SetBinError(i, cor2e); + }; + if (OnPt) { + rethist->SetBinContent(0, rf2); + rethist->SetBinError(0, rf2e); + } else { + rethist->SetBinContent(0, 0); + rethist->SetBinError(0, 0); + }; + return rethist; +}; + +TH1D* FlowContainer::GetCN4(TH1D* corrN4, TH1D* corrN2) +{ + Double_t rf2 = corrN2->GetBinContent(0); + Double_t rf2e = corrN2->GetBinError(0); + Double_t rf4 = corrN4->GetBinContent(0); + Double_t rf4e = corrN4->GetBinError(0); + Bool_t OnPt = (rf2 != 0); + TH1D* rethist = (TH1D*)corrN4->Clone(Form("cN4_%s", corrN4->GetName())); + rethist->Reset(); + for (Int_t i = 1; i <= rethist->GetNbinsX(); i++) { + Double_t cor4v = corrN4->GetBinContent(i); + Double_t cor4e = corrN4->GetBinError(i); + Double_t cor2v = corrN2->GetBinContent(i); + Double_t cor2e = corrN2->GetBinError(i); + rethist->SetBinContent(i, OnPt ? DN4Value(cor4v, cor2v, rf2) : CN4Value(cor4v, cor2v)); + rethist->SetBinError(i, OnPt ? DN4Error(cor4e, cor2v, cor2e, rf2, rf2e) : CN4Error(cor4e, cor2v, cor2e)); + }; + if (OnPt) { + rethist->SetBinContent(0, CN4Value(rf4, rf2)); + rethist->SetBinError(0, CN4Error(rf4e, rf2, rf2e)); + } else { + rethist->SetBinContent(0, 0); + rethist->SetBinError(0, 0); + }; + return rethist; +}; + +TH1D* FlowContainer::GetCN6(TH1D* corrN6, TH1D* corrN4, TH1D* corrN2) +{ + TH1D* tn2 = (TH1D*)corrN2->Clone(Form("tn2_%s", corrN2->GetName())); + TH1D* tn4 = (TH1D*)corrN4->Clone(Form("tn4_%s", corrN4->GetName())); + TH1D* tn6 = (TH1D*)corrN6->Clone(Form("tn6_%s", corrN6->GetName())); + + Double_t rf2 = corrN2->GetBinContent(0); + Double_t rf2e = corrN2->GetBinError(0); + Double_t rf4 = corrN4->GetBinContent(0); + Double_t rf4e = corrN4->GetBinError(0); + Double_t rf6 = corrN6->GetBinContent(0); + Double_t rf6e = corrN6->GetBinError(0); + Bool_t OnPt = (rf2 != 0); + TH1D* rethist = (TH1D*)corrN6->Clone(Form("cN6_%s", corrN6->GetName())); + rethist->Reset(); + for (Int_t i = 1; i <= rethist->GetNbinsX(); i++) { + Double_t cor6v = corrN6->GetBinContent(i); + Double_t cor6e = corrN6->GetBinError(i); + Double_t cor4v = corrN4->GetBinContent(i); + Double_t cor4e = corrN4->GetBinError(i); + Double_t cor2v = corrN2->GetBinContent(i); + Double_t cor2e = corrN2->GetBinError(i); + rethist->SetBinContent(i, OnPt ? DN6Value(cor6v, cor4v, cor2v, rf4, rf2) : CN6Value(cor6v, cor4v, cor2v)); + rethist->SetBinError(i, OnPt ? DN6Error(cor6e, cor4v, cor4e, cor2v, cor2e, rf4, rf4e, rf2, rf2e) : CN6Error(cor6e, cor4v, cor4e, cor2v, cor2e)); + }; + if (OnPt) { + rethist->SetBinContent(0, CN6Value(rf6, rf4, rf2)); + rethist->SetBinError(0, CN6Error(rf6e, rf4, rf4e, rf2, rf2e)); + } else { + rethist->SetBinContent(0, 0); + rethist->SetBinError(0, 0); + }; + delete tn2; + delete tn4; + delete tn6; + return rethist; +}; +TH1D* FlowContainer::GetCN8(TH1D* corrN8, TH1D* corrN6, TH1D* corrN4, TH1D* corrN2) +{ + TH1D* tn2 = (TH1D*)corrN2->Clone(Form("tn2_%s", corrN2->GetName())); + TH1D* tn4 = (TH1D*)corrN4->Clone(Form("tn4_%s", corrN4->GetName())); + TH1D* tn6 = (TH1D*)corrN6->Clone(Form("tn6_%s", corrN6->GetName())); + TH1D* tn8 = (TH1D*)corrN8->Clone(Form("tn8_%s", corrN6->GetName())); + + Double_t rf2 = corrN2->GetBinContent(0); + Double_t rf2e = corrN2->GetBinError(0); + Double_t rf4 = corrN4->GetBinContent(0); + Double_t rf4e = corrN4->GetBinError(0); + Double_t rf6 = corrN6->GetBinContent(0); + Double_t rf6e = corrN6->GetBinError(0); + Double_t rf8 = corrN8->GetBinContent(0); + Double_t rf8e = corrN8->GetBinError(0); + Bool_t OnPt = (rf2 != 0); + TH1D* rethist = (TH1D*)corrN8->Clone(Form("cN8_%s", corrN8->GetName())); + rethist->Reset(); + for (Int_t i = 1; i <= rethist->GetNbinsX(); i++) { + Double_t cor8v = corrN8->GetBinContent(i); + Double_t cor8e = corrN8->GetBinError(i); + Double_t cor6v = corrN6->GetBinContent(i); + Double_t cor6e = corrN6->GetBinError(i); + Double_t cor4v = corrN4->GetBinContent(i); + Double_t cor4e = corrN4->GetBinError(i); + Double_t cor2v = corrN2->GetBinContent(i); + Double_t cor2e = corrN2->GetBinError(i); + rethist->SetBinContent(i, OnPt ? DN8Value(cor8v, cor6v, cor4v, cor2v, rf6, rf4, rf2) : CN8Value(cor8v, cor6v, cor4v, cor2v)); + rethist->SetBinError(i, OnPt ? DN8Error(cor8e, cor6v, cor6e, cor4v, cor4e, cor2v, cor2e, rf6, rf6e, rf4, rf4e, rf2, rf2e) : CN8Error(cor8e, cor6v, cor6e, cor4v, cor4e, cor2v, cor2e)); + }; + if (OnPt) { + rethist->SetBinContent(0, CN8Value(rf8, rf6, rf4, rf2)); + rethist->SetBinError(0, CN8Error(rf8e, rf6, rf6e, rf4, rf4e, rf2, rf2e)); + } else { + rethist->SetBinContent(0, 0); + rethist->SetBinError(0, 0); + }; + delete tn2; + delete tn4; + delete tn6; + delete tn8; + return rethist; +}; + +TH1D* FlowContainer::GetCN4VsX(Int_t n, Bool_t onPt, Double_t arg1, Double_t arg2) +{ + TH1D *corrN2, *corrN4; + if (onPt) { + corrN2 = GetHistCorrXXVsPt(Form("%i2", n), arg1, arg2); + corrN2->SetName(Form("Corr_%s", corrN2->GetName())); + corrN4 = GetHistCorrXXVsPt(Form("%i4", n), arg1, arg2); + corrN4->SetName(Form("Corr_%s", corrN4->GetName())); + } else { + corrN2 = GetHistCorrXXVsMulti(Form("%i2", n), (Int_t)arg1); + corrN2->SetName(Form("Corr_%s", corrN2->GetName())); + corrN4 = GetHistCorrXXVsMulti(Form("%i4", n), (Int_t)arg1); + corrN4->SetName(Form("Corr_%s", corrN4->GetName())); + }; + TH1D* rethist = GetCN4(corrN4, corrN2); + TString* nam = new TString(corrN4->GetName()); + delete corrN2; + delete corrN4; + rethist->SetName(nam->Data()); + if (onPt) { + Int_t bins = fProf->GetXaxis()->FindBin(arg1); + Int_t bins2 = fProf->GetXaxis()->FindBin(arg2); + Double_t bv1 = fProf->GetXaxis()->GetBinLowEdge(bins); + Double_t bv2 = fProf->GetXaxis()->GetBinUpEdge(bins2); + rethist->SetTitle(Form("%2.0f - %4.0f;#it{p}_{T} (GeV/#it{c}); c_{%i}{4}", bv1, bv2, n)); + } else { + rethist->SetTitle(Form(";#it{N}_{tr};c_{%i}{4}", n)); + }; + return rethist; +}; +TH1D* FlowContainer::GetVN4(TH1D* inh) +{ + TH1D* rethist = (TH1D*)inh->Clone(Form("v24_%s", inh->GetName())); + Double_t c4 = inh->GetBinContent(0); + Double_t c4e = inh->GetBinError(0); + Bool_t OnPt = (!c4 == 0); + rethist->Reset(); + for (Int_t i = 1; i <= rethist->GetNbinsX(); i++) { + Double_t d4 = inh->GetBinContent(i); + Double_t d4e = inh->GetBinError(i); + if (OnPt && c4 >= 0) + continue; + //if(d4>=0) continue; + rethist->SetBinContent(i, OnPt ? VDN4Value(d4, c4) : VN4Value(d4)); + rethist->SetBinError(i, OnPt ? VDN4Error(d4, d4e, c4, c4e) : VN4Error(d4, d4e)); + }; + return rethist; +}; +TH1D* FlowContainer::GetVN6(TH1D* inh) +{ + TH1D* rethist = (TH1D*)inh->Clone(Form("v26_%s", inh->GetName())); + Double_t c6 = inh->GetBinContent(0); + Double_t c6e = inh->GetBinError(0); + Bool_t OnPt = (!c6 == 0); + rethist->Reset(); + for (Int_t i = 1; i <= rethist->GetNbinsX(); i++) { + Double_t d6 = inh->GetBinContent(i); + Double_t d6e = inh->GetBinError(i); + if (OnPt && c6 <= 0) + continue; + //if(d6<=0) continue; + rethist->SetBinContent(i, OnPt ? VDN6Value(d6, c6) : VN6Value(d6)); + rethist->SetBinError(i, OnPt ? VDN6Error(d6, d6e, c6, c6e) : VN6Error(d6, d6e)); + }; + return rethist; +}; +TH1D* FlowContainer::GetVN8(TH1D* inh) +{ + TH1D* rethist = (TH1D*)inh->Clone(Form("v28_%s", inh->GetName())); + Double_t c8 = inh->GetBinContent(0); + Double_t c8e = inh->GetBinError(0); + Bool_t OnPt = (!c8 == 0); + rethist->Reset(); + for (Int_t i = 1; i <= rethist->GetNbinsX(); i++) { + Double_t d8 = inh->GetBinContent(i); + Double_t d8e = inh->GetBinError(i); + if (OnPt && c8 > 0) + continue; + //if(d8>0) continue; + rethist->SetBinContent(i, OnPt ? VDN8Value(d8, c8) : VN8Value(d8)); + rethist->SetBinError(i, OnPt ? VDN8Error(d8, d8e, c8, c8e) : VN8Error(d8, d8e)); + }; + return rethist; +}; + +TH1D* FlowContainer::GetVN4VsX(Int_t n, Bool_t onPt, Double_t arg1, Double_t arg2) +{ + TH1D* temph = GetCN4VsX(n, onPt, arg1, arg2); + TH1D* rethist = GetVN4(temph); + TString* nam = new TString(temph->GetName()); + delete temph; + rethist->SetName(nam->Data()); + if (onPt) { + Int_t bins = fProf->GetXaxis()->FindBin(arg1); + Int_t bins2 = fProf->GetXaxis()->FindBin(arg2); + Double_t bv1 = fProf->GetXaxis()->GetBinLowEdge(bins); + Double_t bv2 = fProf->GetXaxis()->GetBinUpEdge(bins2); + rethist->SetTitle(Form("%2.0f - %4.0f;#it{p}_{T} (GeV/#it{c}); v_{%i}{4}", bv1, bv2, n)); + } else { + rethist->SetTitle(Form(";#it{N}_{tr};v_{%i}{4}", n)); + }; + return rethist; +}; +TH1D* FlowContainer::GetCN6VsX(Int_t n, Bool_t onPt, Double_t arg1, Double_t arg2) +{ + TH1D *corrN2, *corrN4, *corrN6; + if (onPt) { + corrN2 = GetHistCorrXXVsPt(Form("%i2", n), arg1, arg2); + corrN2->SetName(Form("Corr_%s", corrN2->GetName())); + corrN4 = GetHistCorrXXVsPt(Form("%i4", n), arg1, arg2); + corrN4->SetName(Form("Corr_%s", corrN4->GetName())); + corrN6 = GetHistCorrXXVsPt(Form("%i6", n), arg1, arg2); + corrN6->SetName(Form("Corr_%s", corrN6->GetName())); + } else { + corrN2 = GetHistCorrXXVsMulti(Form("%i2", n), (Int_t)arg1); + corrN4 = GetHistCorrXXVsMulti(Form("%i4", n), (Int_t)arg1); + corrN6 = GetHistCorrXXVsMulti(Form("%i6", n), (Int_t)arg1); + }; + TH1D* rethist = GetCN6(corrN6, corrN4, corrN2); + delete corrN2; + delete corrN4; + TString* nam = new TString(corrN6->GetName()); + delete corrN6; + rethist->SetName(nam->Data()); + if (onPt) { + Int_t bins = fProf->GetXaxis()->FindBin(arg1); + Int_t bins2 = fProf->GetXaxis()->FindBin(arg2); + Double_t bv1 = fProf->GetXaxis()->GetBinLowEdge(bins); + Double_t bv2 = fProf->GetXaxis()->GetBinUpEdge(bins2); + rethist->SetTitle(Form("%2.0f - %4.0f;#it{p}_{T} (GeV/#it{c}); c_{%i}{6}", bv1, bv2, n)); + } else { + rethist->SetTitle(Form(";#it{N}_{tr};c_{%i}{6}", n)); + }; + return rethist; +}; +TH1D* FlowContainer::GetVN6VsX(Int_t n, Bool_t onPt, Double_t arg1, Double_t arg2) +{ + TH1D* temph = GetCN6VsX(n, onPt, arg1, arg2); + TH1D* rethist = GetVN6(temph); + TString* nam = new TString(temph->GetName()); + delete temph; + rethist->SetName(nam->Data()); + if (onPt) { + Int_t bins = fProf->GetXaxis()->FindBin(arg1); + Int_t bins2 = fProf->GetXaxis()->FindBin(arg2); + Double_t bv1 = fProf->GetXaxis()->GetBinLowEdge(bins); + Double_t bv2 = fProf->GetXaxis()->GetBinUpEdge(bins2); + rethist->SetTitle(Form("%2.0f - %4.0f;#it{p}_{T} (GeV/#it{c}); v_{%i}{6}", bv1, bv2, n)); + } else { + rethist->SetTitle(Form(";#it{N}_{tr};v_{%i}{6}", n)); + }; + return rethist; +}; +TH1D* FlowContainer::GetCN8VsX(Int_t n, Bool_t onPt, Double_t arg1, Double_t arg2) +{ + TH1D *corrN2, *corrN4, *corrN6, *corrN8; + if (onPt) { + corrN2 = GetHistCorrXXVsPt(Form("%i2", n), arg1, arg2); + corrN2->SetName(Form("Corr_%s", corrN2->GetName())); + corrN4 = GetHistCorrXXVsPt(Form("%i4", n), arg1, arg2); + corrN4->SetName(Form("Corr_%s", corrN4->GetName())); + corrN6 = GetHistCorrXXVsPt(Form("%i6", n), arg1, arg2); + corrN6->SetName(Form("Corr_%s", corrN6->GetName())); + corrN8 = GetHistCorrXXVsPt(Form("%i8", n), arg1, arg2); + corrN8->SetName(Form("Corr_%s", corrN8->GetName())); + } else { + corrN2 = GetHistCorrXXVsMulti(Form("%i2", n), (Int_t)arg1); + corrN4 = GetHistCorrXXVsMulti(Form("%i4", n), (Int_t)arg1); + corrN6 = GetHistCorrXXVsMulti(Form("%i6", n), (Int_t)arg1); + corrN8 = GetHistCorrXXVsMulti(Form("%i8", n), (Int_t)arg1); + }; + TH1D* rethist = GetCN8(corrN8, corrN6, corrN4, corrN2); + delete corrN2; + delete corrN4; + delete corrN6; + TString* nam = new TString(corrN8->GetName()); + delete corrN8; + rethist->SetName(nam->Data()); + if (onPt) { + Int_t bins = fProf->GetXaxis()->FindBin(arg1); + Int_t bins2 = fProf->GetXaxis()->FindBin(arg2); + Double_t bv1 = fProf->GetXaxis()->GetBinLowEdge(bins); + Double_t bv2 = fProf->GetXaxis()->GetBinUpEdge(bins2); + rethist->SetTitle(Form("%2.0f - %4.0f;#it{p}_{T} (GeV/#it{c}); c_{%i}{8}", bv1, bv2, n)); + } else { + rethist->SetTitle(Form(";#it{N}_{tr};c_{%i}{8}", n)); + }; + return rethist; +}; +TH1D* FlowContainer::GetVN8VsX(Int_t n, Bool_t onPt, Double_t arg1, Double_t arg2) +{ + TH1D* temph = GetCN8VsX(n, onPt, arg1, arg2); + TH1D* rethist = GetVN8(temph); + TString* nam = new TString(temph->GetName()); + delete temph; + rethist->SetName(nam->Data()); + if (onPt) { + Int_t bins = fProf->GetXaxis()->FindBin(arg1); + Int_t bins2 = fProf->GetXaxis()->FindBin(arg2); + Double_t bv1 = fProf->GetXaxis()->GetBinLowEdge(bins); + Double_t bv2 = fProf->GetXaxis()->GetBinUpEdge(bins2); + rethist->SetTitle(Form("%2.0f - %4.0f;#it{p}_{T} (GeV/#it{c}); v_{%i}{8}", bv1, bv2, n)); + } else { + rethist->SetTitle(Form(";#it{N}_{tr};v_{%i}{8}", n)); + }; + return rethist; +}; +TH1D* FlowContainer::GetCNN(Int_t n, Int_t c, Bool_t onPt, Double_t arg1, Double_t arg2) +{ + if (c == 8) + return GetCN8VsX(n, onPt, arg1, arg2); + if (c == 6) + return GetCN6VsX(n, onPt, arg1, arg2); + if (c == 4) + return GetCN4VsX(n, onPt, arg1, arg2); + return GetCN2VsX(n, onPt, arg1, arg2); +}; +TH1D* FlowContainer::GetVNN(Int_t n, Int_t c, Bool_t onPt, Double_t arg1, Double_t arg2) +{ + if (c == 8) + return GetVN8VsX(n, onPt, arg1, arg2); + if (c == 6) + return GetVN6VsX(n, onPt, arg1, arg2); + if (c == 4) + return GetVN4VsX(n, onPt, arg1, arg2); + return GetVN2VsX(n, onPt, arg1, arg2); +}; +TProfile* FlowContainer::GetRefFlowProfile(const char* order, Double_t m1, Double_t m2) +{ + Int_t nStartBin = fProf->GetXaxis()->FindBin(m1 + 0.001); + Int_t nStopBin = fProf->GetXaxis()->FindBin(m2 - 0.001); + if (nStartBin == 0) + nStartBin = 1; + if (nStopBin < nStartBin) + nStopBin = fProf->GetXaxis()->GetNbins(); + Int_t nBins = nStopBin - nStartBin + 1; + Double_t* l_bins = new Double_t[nBins + 1]; + for (Int_t i = 0; i <= nBins; i++) + l_bins[i] = i; //dummy bins, will be merged anyways + TProfile* retpf = 0; + TString l_name(""); + Ssiz_t l_pos = 0; + ProfileSubset* rhSubset = new ProfileSubset(*fProf); + rhSubset->GetXaxis()->SetRange(nStartBin, nStopBin); + while (fIDName.Tokenize(l_name, l_pos)) { + l_name.Append(order); + Int_t ybin = fProf->GetYaxis()->FindBin(l_name.Data()); + TProfile* tempprof = rhSubset->GetSubset(kTRUE, "tempprof", ybin, ybin, nBins, l_bins); + if (!retpf) + retpf = (TProfile*)tempprof->Clone("RefFlowProf"); + else + retpf->Add(tempprof); + delete tempprof; + }; + delete rhSubset; + retpf->RebinX(nBins); + return retpf; +}; + +//{2} particle correlations +Double_t FlowContainer::CN2Value(Double_t cor2) +{ + if (!fPropagateErrors) + return 0; + return cor2; +}; +Double_t FlowContainer::CN2Error(Double_t cor2e) +{ + if (!fPropagateErrors) + return 0; + return cor2e; +}; +Double_t FlowContainer::VN2Value(Double_t cor2) +{ + if (cor2 < 0) + return -2; //Return -2, which is not ok + return TMath::Sqrt(cor2); +}; +Double_t FlowContainer::VN2Error(Double_t cor2, Double_t cor2e) +{ + if (cor2 < 0) + return 0; + if (!fPropagateErrors) + return 0; + return 0.5 * cor2e / TMath::Sqrt(cor2); +}; +Double_t FlowContainer::VDN2Value(Double_t cor2d, Double_t cor2) +{ + if (cor2 < 0) + return -2; //Return -2, which is not ok + return cor2d / TMath::Sqrt(cor2); +}; +Double_t FlowContainer::VDN2Error(Double_t cor2d, Double_t cor2de, Double_t cor2, Double_t cor2e) +{ + if (!fPropagateErrors) + return 0; + Double_t sqrtv = cor2de * cor2de / cor2 + 0.25 * cor2d * cor2d * cor2e * cor2e / (cor2 * cor2 * cor2); + if (sqrtv < 0) + return 0; + return TMath::Sqrt(sqrtv); +}; + +//C{4} and V{4} calculations +Double_t FlowContainer::CN4Value(Double_t cor4, Double_t cor2) +{ + return cor4 - 2 * TMath::Power(cor2, 2); +}; +Double_t FlowContainer::CN4Error(Double_t cor4e, Double_t cor2, Double_t cor2e) +{ + if (!fPropagateErrors) + return 0; + return TMath::Sqrt(cor4e * cor4e + 16 * cor2 * cor2 * cor2e * cor2e); +}; +Double_t FlowContainer::DN4Value(Double_t cor4d, Double_t cor2d, Double_t cor2) +{ + return cor4d - 2 * cor2d * cor2; +}; +Double_t FlowContainer::DN4Error(Double_t cor4de, Double_t cor2d, Double_t cor2de, Double_t cor2, Double_t cor2e) +{ + if (!fPropagateErrors) + return 0; + return TMath::Sqrt(cor4de * cor4de + 4 * cor2 * cor2 * cor2de * cor2de + 4 * cor2d * cor2d * cor2e * cor2e); +}; +Double_t FlowContainer::VN4Value(Double_t c4) +{ + if (c4 > 0) + return -2; //Return -2 if cannot calculate + return TMath::Power(-c4, 1. / 4); +}; +Double_t FlowContainer::VN4Error(Double_t c4, Double_t c4e) +{ + if (c4 > 0) + return 0; + if (!fPropagateErrors) + return 0; + return TMath::Power(-c4, (-3. / 4)) * c4e / 4; +}; +Double_t FlowContainer::VDN4Value(Double_t d4, Double_t c4) +{ + if (c4 > 0) + return -2; //Return -2 if cannot calculate + return -d4 * TMath::Power(-c4, (-3. / 4)); +}; +Double_t FlowContainer::VDN4Error(Double_t d4, Double_t d4e, Double_t c4, Double_t c4e) +{ + if (!fPropagateErrors) + return 0; + if (c4 > 0) + return 0; + return TMath::Sqrt(TMath::Power(-c4, -6. / 4) * d4e * d4e + + TMath::Power(-c4, -14. / 4) * d4 * d4 * c4e * c4e * 9. / 16); +}; + +//{6} particle correlations + +Double_t FlowContainer::CN6Value(Double_t cor6, Double_t cor4, Double_t cor2) +{ + return cor6 - 9 * cor2 * cor4 + 12 * cor2 * cor2 * cor2; +}; +Double_t FlowContainer::CN6Error(Double_t cor6e, Double_t cor4, Double_t cor4e, Double_t cor2, Double_t cor2e) +{ + if (!fPropagateErrors) + return 0; + Double_t inters[3]; + inters[0] = cor6e; + inters[1] = -9 * cor2 * cor4e; + inters[2] = (-9 * cor4 + 36 * cor2 * cor2) * cor2e; + Double_t sum = 0; + for (Int_t i = 0; i < 3; i++) + sum += (inters[i] * inters[i]); + return TMath::Sqrt(sum); +}; +Double_t FlowContainer::DN6Value(Double_t cor6d, Double_t cor4d, Double_t cor2d, Double_t cor4, Double_t cor2) +{ + return cor6d - 6 * cor4d * cor2 - 3 * cor2d * cor4 + 12 * cor2d * cor2 * cor2; +}; +Double_t FlowContainer::DN6Error(Double_t d6e, Double_t d4, Double_t d4e, Double_t d2, + Double_t d2e, Double_t c4, Double_t c4e, Double_t c2, + Double_t c2e) +{ + if (!fPropagateErrors) + return 0; + Double_t inters[5]; + inters[0] = d6e; + inters[1] = -6 * c2 * d4e; + inters[2] = (-3 * c4 + 12 * c2 * c2) * d2e; + inters[3] = -3 * d2 * c4e; + inters[4] = (-6 * d4 + 24 * d2 * c2) * c2e; + Double_t sum = 0; + for (Int_t i = 0; i < 5; i++) + sum += (inters[i] * inters[i]); + return TMath::Sqrt(sum); +}; +Double_t FlowContainer::VN6Value(Double_t c6) +{ + if (c6 < 0) + return -2; //Return -2 if not ok + return TMath::Power(c6 / 4, 1. / 6); +}; +Double_t FlowContainer::VN6Error(Double_t c6, Double_t c6e) +{ + if (c6 < 0) + return 0; + if (!fPropagateErrors) + return 0; + return c6e / 6 * TMath::Power(4, -1. / 6) * TMath::Power(c6, -5. / 6); +}; +Double_t FlowContainer::VDN6Value(Double_t d6, Double_t c6) +{ + if (c6 < 0) + return -2; //Return -2 if not ok + return d6 * TMath::Power(4, -1. / 6) * TMath::Power(c6, -5. / 6); +}; +Double_t FlowContainer::VDN6Error(Double_t d6, Double_t d6e, Double_t c6, Double_t c6e) +{ + if (!fPropagateErrors) + return 0; + if (c6 < 0) + return 0; + if (d6 == 0) + return 0; + Double_t vdn6 = VDN6Value(d6, c6); + Double_t dp = d6e / d6; + Double_t cp = 5 * c6e / 6; + return vdn6 * TMath::Sqrt(dp * dp + cp * cp); +}; + +// {8} particle correlations + +Double_t FlowContainer::CN8Value(Double_t cor8, Double_t cor6, Double_t cor4, Double_t cor2) +{ + return cor8 - 16 * cor6 * cor2 - 18 * cor4 * cor4 + 144 * cor4 * cor2 * cor2 - 144 * cor2 * cor2 * cor2 * cor2; +}; +Double_t FlowContainer::CN8Error(Double_t cor8e, Double_t cor6, Double_t cor6e, + Double_t cor4, Double_t cor4e, Double_t cor2, Double_t cor2e) +{ + if (!fPropagateErrors) + return 0; + Double_t parts[4]; + parts[0] = cor8e; + parts[1] = -16 * cor2 * cor6e; + parts[2] = (-36 * cor4 + 144 * cor2 * cor2) * cor4e; + parts[3] = (-16 * cor6 + 288 * cor4 * cor2 + 576 * cor2 * cor2 * cor2) * cor2e; + Double_t retval = 0; + for (Int_t i = 0; i < 4; i++) + retval += TMath::Power(parts[i], 2); + return TMath::Sqrt(retval); +}; +Double_t FlowContainer::DN8Value(Double_t cor8d, Double_t cor6d, Double_t cor4d, Double_t cor2d, Double_t cor6, Double_t cor4, Double_t cor2) +{ + return cor8d - 12 * cor6d * cor2 - 4 * cor2d * cor6 - 18 * cor4d * cor4 + 72 * cor4d * cor2 * cor2 + 72 * cor4 * cor2 * cor2d - 144 * cor2d * cor2 * cor2 * cor2; +}; +Double_t FlowContainer::DN8Error(Double_t d8e, Double_t d6, Double_t d6e, Double_t d4, + Double_t d4e, Double_t d2, Double_t d2e, Double_t c6, + Double_t c6e, Double_t c4, Double_t c4e, Double_t c2, + Double_t c2e) +{ + if (!fPropagateErrors) + return 0; + Double_t parts[7]; + parts[0] = d8e; //d/d8' + parts[1] = -12 * c2 * d6e; //d/d6' + parts[2] = -4 * d2 * c6e; //d/d6 + parts[3] = (-16 * c4 + 72 * d2) * d4e; //d/d4' + parts[4] = (-16 * d4 + 72 * c2 * d2) * c4e; //d/d4 + parts[5] = (-4 * c6 + 72 * c4 * c2 - 144 * c2 * c2 * c2) * d2e; + parts[6] = (-12 * d6 + 144 * d4 * c2 + 72 * c4 * d2 - 432 * d2 * c2 * c2) * c2e; + Double_t retval = 0; + for (Int_t i = 0; i < 7; i++) + retval += TMath::Power(parts[i], 2); + return TMath::Sqrt(retval); +}; +Double_t FlowContainer::VN8Value(Double_t c8) +{ + if (c8 > 0) + return -2; //Return -2 if not ok + return TMath::Power(-c8 / 33, 1. / 8); +}; +Double_t FlowContainer::VN8Error(Double_t c8, Double_t c8e) +{ + if (c8 > 0) + return 0; + if (!fPropagateErrors) + return 0; + return c8e * 1. / (8 * c8) * VN8Value(c8); +}; +Double_t FlowContainer::VDN8Value(Double_t d8, Double_t c8) +{ + if (c8 > 0) + return -2; //Return -2 if not OK + return d8 / c8 * VN8Value(c8); +}; +Double_t FlowContainer::VDN8Error(Double_t d8, Double_t d8e, Double_t c8, Double_t c8e) +{ + if (c8 > 0) + return 1; + if (d8 == 0) + return 1; + if (!fPropagateErrors) + return 0; + Double_t vdn8v = VDN8Value(d8, c8); + Double_t dd = d8e / d8; + Double_t dc = -7 * c8e / (8 * c8); + return vdn8v * TMath::Sqrt(dd * dd + dc * dc); +}; +void FlowContainer::SetPtRebin(Int_t nbins, Double_t* binedges) +{ + fPtRebin = nbins; + fPtRebinEdges = binedges; + return; + Int_t fPtRebin = 0; + //Double_t *lPtRebinEdges=binedges; + if (!fbinsPt) + SetXAxis(); + for (Int_t i = 0; i < nbins; i++) + if (binedges[i] < fbinsPt[0] || binedges[i] > fbinsPt[fNbinsPt - 1]) + continue; + else + fPtRebin++; + if (fPtRebinEdges) + delete[] fPtRebinEdges; + fPtRebinEdges = new Double_t[fPtRebin]; + fPtRebin = 0; + for (Int_t i = 0; i < nbins; i++) + if (binedges[i] < fbinsPt[0] || binedges[i] > fbinsPt[fNbinsPt]) + continue; + else + fPtRebinEdges[fPtRebin++] = binedges[i]; + //fPtRebin--; +} +void FlowContainer::SetMultiRebin(Int_t nbins, Double_t* binedges) +{ + if (fMultiRebinEdges) { + delete[] fMultiRebinEdges; + fMultiRebinEdges = 0; + }; + if (nbins <= 0) { + fMultiRebin = 0; + return; + }; + fMultiRebin = nbins; + fMultiRebinEdges = new Double_t[nbins + 1]; + for (Int_t i = 0; i <= fMultiRebin; i++) + fMultiRebinEdges[i] = binedges[i]; +} +Double_t* FlowContainer::GetMultiRebin(Int_t& nbins) +{ + if (fMultiRebin <= 0) { + nbins = 0; + return 0; + }; + nbins = fMultiRebin; + Double_t* retBins = new Double_t[fMultiRebin + 1]; + for (Int_t i = 0; i <= nbins; i++) + retBins[i] = fMultiRebinEdges[i]; + return fMultiRebinEdges; +} \ No newline at end of file diff --git a/Analysis/Tasks/PWGCF/GenericFramework/src/GFW.cxx b/Analysis/Tasks/PWGCF/GenericFramework/src/GFW.cxx new file mode 100644 index 0000000000000..80d7a71a6c369 --- /dev/null +++ b/Analysis/Tasks/PWGCF/GenericFramework/src/GFW.cxx @@ -0,0 +1,412 @@ +/* +Author: Vytautas Vislavicius +Extention of Generic Flow (https://arxiv.org/abs/1312.3572) +*/ +#include "GenericFramework/GFW.h" + +GFW::GFW() : fInitialized(kFALSE){}; + +GFW::~GFW() +{ + for (auto pItr = fCumulants.begin(); pItr != fCumulants.end(); ++pItr) + pItr->DestroyComplexVectorArray(); +}; + +void GFW::AddRegion(TString refName, Int_t lNhar, Int_t lNpar, Double_t lEtaMin, Double_t lEtaMax, Int_t lNpT, Int_t BitMask) +{ + if (lNpT < 1) { + printf("Number of pT bins cannot be less than 1! Not adding anything.\n"); + return; + }; + if (lEtaMin >= lEtaMax) { + printf("Eta min. cannot be more than eta max! Not adding...\n"); + return; + }; + if (refName.EqualTo("")) { + printf("Region must have a name!\n"); + return; + }; + Region lOneRegion; + lOneRegion.Nhar = lNhar; //Number of harmonics + lOneRegion.Npar = lNpar; //Number of powers + lOneRegion.NparVec = vector{}; //if powers defined, then set this to empty vector + lOneRegion.EtaMin = lEtaMin; //Min. eta + lOneRegion.EtaMax = lEtaMax; //Max. eta + lOneRegion.NpT = lNpT; //Number of pT bins + lOneRegion.rName = refName; //Name of the region + lOneRegion.BitMask = BitMask; //Bit mask + AddRegion(lOneRegion); +}; +void GFW::AddRegion(TString refName, Int_t lNhar, Int_t* lNparVec, Double_t lEtaMin, Double_t lEtaMax, Int_t lNpT, Int_t BitMask) +{ + if (lNpT < 1) { + printf("Number of pT bins cannot be less than 1! Not adding anything.\n"); + return; + }; + if (lEtaMin >= lEtaMax) { + printf("Eta min. cannot be more than eta max! Not adding...\n"); + return; + }; + if (refName.EqualTo("")) { + printf("Region must have a name!\n"); + return; + }; + Region lOneRegion; + lOneRegion.Nhar = lNhar; //Number of harmonics + lOneRegion.Npar = 0; //If vector with powers defined, set this to zero + lOneRegion.NparVec = vector{}; //lNparVec; //vector with powers for each harmonic + for (Int_t i = 0; i < lNhar; i++) + lOneRegion.NparVec.push_back(lNparVec[i]); + lOneRegion.EtaMin = lEtaMin; //Min. eta + lOneRegion.EtaMax = lEtaMax; //Max. eta + lOneRegion.NpT = lNpT; //Number of pT bins + lOneRegion.rName = refName; //Name of the region + lOneRegion.BitMask = BitMask; //Bit mask + AddRegion(lOneRegion); +}; +void GFW::SplitRegions(){ + //Simple case. Will not look for overlaps, etc. Everything is left for end-used +}; + +Int_t GFW::CreateRegions() +{ + if (fRegions.size() < 1) { + printf("No regions set. Skipping...\n"); + return 0; + }; + SplitRegions(); + //for(auto pitr = fRegions.begin(); pitr!=fRegions.end(); pitr++) pitr->PrintStructure(); + Int_t nRegions = 0; + for (auto pItr = fRegions.begin(); pItr != fRegions.end(); pItr++) { + GFWCumulant* lCumulant = new GFWCumulant(); + if (pItr->NparVec.size()) { + lCumulant->CreateComplexVectorArrayVarPower(pItr->Nhar, pItr->NparVec, pItr->NpT); + } else { + lCumulant->CreateComplexVectorArray(pItr->Nhar, pItr->Npar, pItr->NpT); + }; + fCumulants.push_back(*lCumulant); + ++nRegions; + }; + if (nRegions) + fInitialized = kTRUE; + return nRegions; +}; + +void GFW::Fill(Double_t eta, Int_t ptin, Double_t phi, Double_t weight, Int_t mask, Double_t SecondWeight) +{ + if (!fInitialized) + CreateRegions(); + if (!fInitialized) + return; + for (Int_t i = 0; i < (Int_t)fRegions.size(); ++i) { + if (fRegions.at(i).EtaMin < eta && fRegions.at(i).EtaMax > eta && (fRegions.at(i).BitMask & mask)) + fCumulants.at(i).FillArray(eta, ptin, phi, weight, SecondWeight); + }; +}; +TComplex GFW::TwoRec(Int_t n1, Int_t n2, Int_t p1, Int_t p2, Int_t ptbin, GFWCumulant* r1, GFWCumulant* r2, GFWCumulant* r3) +{ + TComplex part1 = r1->Vec(n1, p1, ptbin); + TComplex part2 = r2->Vec(n2, p2, ptbin); + TComplex part3 = r3 ? r3->Vec(n1 + n2, p1 + p2, ptbin) : TComplex(0, 0); + TComplex formula = part1 * part2 - part3; + return formula; +}; +TComplex GFW::RecursiveCorr(GFWCumulant* qpoi, GFWCumulant* qref, GFWCumulant* qol, Int_t ptbin, vector& hars) +{ + vector pows; + for (Int_t i = 0; i < (Int_t)hars.size(); i++) + pows.push_back(1); + return RecursiveCorr(qpoi, qref, qol, ptbin, hars, pows); +}; + +TComplex GFW::RecursiveCorr(GFWCumulant* qpoi, GFWCumulant* qref, GFWCumulant* qol, Int_t ptbin, vector& hars, vector& pows) +{ + if ((pows.at(0) != 1) && qol) + qpoi = qol; //if the power of POI is not unity, then always use overlap (if defined). + //Only valid for 1 particle of interest though! + if (hars.size() < 2) + return qpoi->Vec(hars.at(0), pows.at(0), ptbin); + if (hars.size() < 3) + return TwoRec(hars.at(0), hars.at(1), pows.at(0), pows.at(1), ptbin, qpoi, qref, qol); + Int_t harlast = hars.at(hars.size() - 1); + Int_t powlast = pows.at(pows.size() - 1); + hars.erase(hars.end() - 1); + pows.erase(pows.end() - 1); + TComplex formula = RecursiveCorr(qpoi, qref, qol, ptbin, hars, pows) * qref->Vec(harlast, powlast); + Int_t lDegeneracy = 1; + Int_t harSize = (Int_t)hars.size(); + for (Int_t i = harSize - 1; i >= 0; i--) { + //checking if current configuration is a permutation of the next one. + //Need to have more than 2 harmonics though, otherwise it doesn't make sense. + if (i > 2) { //only makes sense when we have more than two harmonics remaining + if (hars.at(i) == hars.at(i - 1) && pows.at(i) == pows.at(i - 1)) { //if it is a permutation, then increase degeneracy and continue; + lDegeneracy++; + continue; + }; + } + hars.at(i) += harlast; + pows.at(i) += powlast; + //The issue is here. In principle, if i=0 (dif), then the overlap is only qpoi (0, if no overlap); + //Otherwise, if we are not working with the 1st entry (dif.), then overlap will always be from qref + //One should thus (probably) make a check if i=0, then qovl=qpoi, otherwise qovl=qref. But need to think more + //-- This is not aplicable anymore, since the overlap is explicitly specified + TComplex subtractVal = RecursiveCorr(qpoi, qref, qol, ptbin, hars, pows); + if (lDegeneracy > 1) { + subtractVal *= lDegeneracy; + lDegeneracy = 1; + }; + formula -= subtractVal; + hars.at(i) -= harlast; + pows.at(i) -= powlast; + }; + hars.push_back(harlast); + pows.push_back(powlast); + return formula; +}; +void GFW::Clear() +{ + for (auto ptr = fCumulants.begin(); ptr != fCumulants.end(); ++ptr) + ptr->ResetQs(); + fCalculatedNames.clear(); + fCalculatedQs.clear(); +}; +TComplex GFW::Calculate(TString config, Bool_t SetHarmsToZero) +{ + if (config.EqualTo("")) { + printf("Configuration empty!\n"); + return TComplex(0, 0); + }; + TString tmp; + Ssiz_t sz1 = 0; + TComplex ret(1, 0); + while (config.Tokenize(tmp, sz1, "}")) { + if (SetHarmsToZero) + SetHarmonicsToZero(tmp); + /*Int_t ind=FindCalculated(tmp); + if(ind>=0) { + ret*=fCalculatedQs.at(ind); + continue; + };*/ + TComplex val = CalculateSingle(tmp); + ret *= val; + fCalculatedQs.push_back(val); + fCalculatedNames.push_back(tmp); + }; + return ret; +}; +TComplex GFW::CalculateSingle(TString config) +{ + //First remove all ; and ,: + config.ReplaceAll(",", " "); + config.ReplaceAll(";", " "); + //Then make sure we don't have any double-spaces: + while (config.Index(" ") > -1) + config.ReplaceAll(" ", " "); + vector regs; + vector hars; + Int_t ptbin = 0; + Ssiz_t sz1 = 0; + Ssiz_t szend = 0; + TString ts, ts2; + //find the pT-bin: + if (config.Tokenize(ts, sz1, "(")) { + config.Tokenize(ts, sz1, ")"); + ptbin = ts.Atoi(); + }; + //Fetch region descriptor + if (sz1 < 0) + sz1 = 0; + if (!config.Tokenize(ts, szend, "{")) { + printf("Could not find harmonics!\n"); + return TComplex(0, 0); + }; + //Fetch regions + while (ts.Tokenize(ts2, sz1, " ")) { + if (sz1 >= szend) + break; + Int_t ind = FindRegionByName(ts2); + if (ts2.EqualTo(" ") || ts2.EqualTo("")) + continue; + if (ind < 0) { + printf("Could not find region named %s!\n", ts2.Data()); + break; + }; + regs.push_back(ind); + }; + //Fetch harmonics + while (config.Tokenize(ts, szend, " ")) + hars.push_back(ts.Atoi()); + if (regs.size() == 1) + return Calculate(regs.at(0), hars); + return Calculate(regs.at(0), regs.at(1), hars, ptbin); +}; +GFW::CorrConfig GFW::GetCorrelatorConfig(TString config, TString head, Bool_t ptdif) +{ + //First remove all ; and ,: + config.ReplaceAll(",", " "); + config.ReplaceAll(";", " "); + config.ReplaceAll("| ", "|"); + //Then make sure we don't have any double-spaces: + while (config.Index(" ") > -1) + config.ReplaceAll(" ", " "); + vector regs; + vector hars; + Int_t ptbin = 0; + Ssiz_t sz1 = 0; + Ssiz_t szend = 0; + TString ts, ts2; + CorrConfig ReturnConfig; + //find the pT-bin: + if (config.Tokenize(ts, sz1, "(")) { + config.Tokenize(ts, sz1, ")"); + ptbin = ts.Atoi(); + }; + //Fetch region descriptor + if (sz1 < 0) + sz1 = 0; + + if (!config.Tokenize(ts, szend, "{")) { + printf("Could not find harmonics!\n"); + return ReturnConfig; + }; + szend = 0; + Int_t counter = 0; + while (config.Tokenize(ts, szend, "{")) { + counter++; + ReturnConfig.Regs.push_back(vector{}); + ReturnConfig.Hars.push_back(vector{}); + ReturnConfig.Overlap.push_back(-1); //initially, assume no overlap + sz1 = 0; + //Fetch regions + while (ts.Tokenize(ts2, sz1, " ")) { + if (sz1 >= szend) + break; + Bool_t isOverlap = ts2.Contains("|"); + if (isOverlap) + ts2.Remove(0, 1); //If overlap, remove the delimiter | + Int_t ind = FindRegionByName(ts2); + if (ts2.EqualTo(" ") || ts2.EqualTo("")) + continue; + if (ind < 0) { + printf("Could not find region named %s!\n", ts2.Data()); + break; + }; + if (!isOverlap) + ReturnConfig.Regs.at(counter - 1).push_back(ind); + else + ReturnConfig.Overlap.at((int)ReturnConfig.Overlap.size() - 1) = ind; + /* if(counter==1) { + if(!isOverlap) + ReturnConfig.Regs.push_back(ind); + else ReturnConfig.Overlap1 = ind; + } else { + if(!isOverlap) + ReturnConfig.Regs2.push_back(ind); + else ReturnConfig.Overlap2 = ind; + }*/ + }; + TString harstr; + config.Tokenize(harstr, szend, "}"); + Ssiz_t dummys = 0; + //Fetch harmonics + while (harstr.Tokenize(ts, dummys, " ")) + ReturnConfig.Hars.at(counter - 1).push_back(ts.Atoi()); + // if(counter==1) + // while(harstr.Tokenize(ts,dummys," ")) ReturnConfig.Hars.push_back(ts.Atoi()); + // else + // while(harstr.Tokenize(ts,dummys," ")) ReturnConfig.Hars2.push_back(ts.Atoi()); + }; + ReturnConfig.Head = head; + ReturnConfig.pTDif = ptdif; + return ReturnConfig; +}; + +TComplex GFW::Calculate(Int_t poi, Int_t ref, vector hars, Int_t ptbin) +{ + GFWCumulant* qref = &fCumulants.at(ref); + GFWCumulant* qpoi = &fCumulants.at(poi); + GFWCumulant* qovl = qpoi; + return RecursiveCorr(qpoi, qref, qovl, ptbin, hars); +}; +TComplex GFW::Calculate(CorrConfig corconf, Int_t ptbin, Bool_t SetHarmsToZero, Bool_t DisableOverlap) +{ + if (corconf.Regs.size() == 0) + return TComplex(0, 0); //Check if we have any regions at all + TComplex retval(1, 1); + for (Int_t i = 0; i < (Int_t)corconf.Regs.size(); i++) { //looping over all regions + if (corconf.Regs.at(i).size() == 0) + return TComplex(0, 0); //again, if no regions in the current subevent, then quit immediatelly + //picking up the indecies of regions... + Int_t poi = corconf.Regs.at(i).at(0); + Int_t ref = (corconf.Regs.at(i).size() > 1) ? corconf.Regs.at(i).at(1) : corconf.Regs.at(i).at(0); + Int_t ovl = corconf.Overlap.at(i); + //and regions themselves + GFWCumulant* qref = &fCumulants.at(ref); + GFWCumulant* qpoi = &fCumulants.at(poi); + if (!qref->IsPtBinFilled(ptbin)) + return TComplex(0, 0); //if REF is not filled, don't even continue. Could be redundant, but should save little CPU time + if (!qpoi->IsPtBinFilled(ptbin)) + return TComplex(0, 0); //if POI is not filled, don't even continue. Could be redundant, but should save little CPU time + GFWCumulant* qovl = 0; + //Check if in the ref. region we have enough particles (no. of particles in the region >= no of harmonics for subevent) + Int_t sz1 = corconf.Hars.at(i).size(); + if (poi != ref) + sz1--; + if (qref->GetN() < sz1) + return TComplex(0, 0); + //Then, figure the overlap + if (ovl > -1) //if overlap is defined, then (unless it's explicitly disabled) + qovl = DisableOverlap ? 0 : &fCumulants.at(ovl); + else if (ref == poi) + qovl = qref; //If ref and poi are the same, then the same is for overlap. Only, when OL not explicitly defined + if (SetHarmsToZero) + for (Int_t j = 0; j < (Int_t)corconf.Hars.at(i).size(); j++) + corconf.Hars.at(i).at(j) = 0; + retval *= RecursiveCorr(qpoi, qref, qovl, ptbin, corconf.Hars.at(i)); + } + return retval; +}; + +TComplex GFW::Calculate(Int_t poi, vector hars) +{ + GFWCumulant* qpoi = &fCumulants.at(poi); + return RecursiveCorr(qpoi, qpoi, qpoi, 0, hars); +}; +Int_t GFW::FindRegionByName(TString refName) +{ + for (Int_t i = 0; i < (Int_t)fRegions.size(); i++) + if (fRegions.at(i).rName.EqualTo(refName)) + return i; + return -1; +}; +Int_t GFW::FindCalculated(TString identifier) +{ + if (fCalculatedNames.size() == 0) + return -1; + for (Int_t i = 0; i < (Int_t)fCalculatedNames.size(); i++) { + if (fCalculatedNames.at(i).EqualTo(identifier)) + return i; + }; + return -1; +}; +Bool_t GFW::SetHarmonicsToZero(TString& instr) +{ + TString tmp; + Ssiz_t sz1 = 0, sz2; + if (!instr.Tokenize(tmp, sz1, "{")) { + printf("GFW::SetHarmonicsToZero: could not find \"{\" token in %s\n", instr.Data()); + return kFALSE; + }; + sz2 = sz1; + Int_t indc = 0; + while (instr.Tokenize(tmp, sz1, " ")) + indc++; + if (!indc) { + printf("GFW::SetHarmonicsToZero: did not find any harmonics in %s, nothing to replace\n", instr.Data()); + return kFALSE; + }; + instr.Remove(sz2); + for (Int_t i = 0; i < indc; i++) + instr.Append("0 "); + return kTRUE; +}; \ No newline at end of file diff --git a/Analysis/Tasks/PWGCF/GenericFramework/src/GFWCumulant.cxx b/Analysis/Tasks/PWGCF/GenericFramework/src/GFWCumulant.cxx new file mode 100644 index 0000000000000..afca6e72fa749 --- /dev/null +++ b/Analysis/Tasks/PWGCF/GenericFramework/src/GFWCumulant.cxx @@ -0,0 +1,118 @@ + +/* +Author: Vytautas Vislavicius +Extention of Generic Flow (https://arxiv.org/abs/1312.3572) +*/ +#include "GenericFramework/GFWCumulant.h" + +GFWCumulant::GFWCumulant() : fQvector(0), + fUsed(kBlank), + fNEntries(-1), + fN(1), + fPow(1), + fPt(1), + fFilledPts(0), + fInitialized(kFALSE){}; + +GFWCumulant::~GFWCumulant(){ + //printf("Destructor (?) for some reason called?\n"); + //DestroyComplexVectorArray(); +}; +void GFWCumulant::FillArray(Double_t eta, Int_t ptin, Double_t phi, Double_t weight, Double_t SecondWeight) +{ + if (!fInitialized) + CreateComplexVectorArray(1, 1, 1); + if (fPt == 1) + ptin = 0; //If one bin, then just fill it straight; otherwise, if ptin is out-of-range, do not fill + else if (ptin < 0 || ptin >= fPt) + return; + fFilledPts[ptin] = kTRUE; + for (Int_t lN = 0; lN < fN; lN++) { + Double_t lSin = TMath::Sin(lN * phi); //No need to recalculate for each power + Double_t lCos = TMath::Cos(lN * phi); //No need to recalculate for each power + for (Int_t lPow = 0; lPow < PW(lN); lPow++) { + Double_t lPrefactor = 0; + //Dont calculate it twice; multiplication is cheaper that power + //Also, if second weight is specified, then keep the first weight with power no more than 1, and us the other weight otherwise + //this is important when POIs are a subset of REFs and have different weights than REFs + if (SecondWeight > 0 && lPow > 1) + lPrefactor = TMath::Power(SecondWeight, lPow - 1) * weight; + else + lPrefactor = TMath::Power(weight, lPow); + Double_t qsin = lPrefactor * lSin; + Double_t qcos = lPrefactor * lCos; + fQvector[ptin][lN][lPow](fQvector[ptin][lN][lPow].Re() + qcos, fQvector[ptin][lN][lPow].Im() + qsin); //+=TComplex(qcos,qsin); + }; + }; + Inc(); +}; +void GFWCumulant::ResetQs() +{ + if (!fNEntries) + return; //If 0 entries, then no need to reset. Otherwise, if -1, then just initialized and need to set to 0. + for (Int_t i = 0; i < fPt; i++) { + fFilledPts[i] = kFALSE; + for (Int_t lN = 0; lN < fN; lN++) { + for (Int_t lPow = 0; lPow < PW(lN); lPow++) { + fQvector[i][lN][lPow](0., 0.); + }; + }; + }; + fNEntries = 0; +}; +void GFWCumulant::DestroyComplexVectorArray() +{ + if (!fInitialized) + return; + for (Int_t l_n = 0; l_n < fN; l_n++) { + for (Int_t i = 0; i < fPt; i++) { + delete[] fQvector[i][l_n]; + }; + }; + for (Int_t i = 0; i < fPt; i++) { + delete[] fQvector[i]; + }; + delete[] fQvector; + delete[] fFilledPts; + fInitialized = kFALSE; + fNEntries = -1; +}; + +void GFWCumulant::CreateComplexVectorArray(Int_t N, Int_t Pow, Int_t Pt) +{ + DestroyComplexVectorArray(); + vector pwv; + for (Int_t i = 0; i < N; i++) + pwv.push_back(Pow); + CreateComplexVectorArrayVarPower(N, pwv, Pt); +}; +void GFWCumulant::CreateComplexVectorArrayVarPower(Int_t N, vector PowVec, Int_t Pt) +{ + DestroyComplexVectorArray(); + fN = N; + fPow = 0; + fPt = Pt; + fFilledPts = new Bool_t[Pt]; + fPowVec = PowVec; + fQvector = new TComplex**[fPt]; + for (Int_t i = 0; i < fPt; i++) { + fQvector[i] = new TComplex*[fN]; + }; + for (Int_t l_n = 0; l_n < fN; l_n++) { + for (Int_t i = 0; i < fPt; i++) { + fQvector[i][l_n] = new TComplex[PW(l_n)]; + }; + }; + ResetQs(); + fInitialized = kTRUE; +}; +TComplex GFWCumulant::Vec(Int_t n, Int_t p, Int_t ptbin) +{ + if (!fInitialized) + return 0; + if (ptbin >= fPt || ptbin < 0) + ptbin = 0; + if (n >= 0) + return fQvector[ptbin][n][p]; + return TComplex::Conjugate(fQvector[ptbin][-n][p]); +}; \ No newline at end of file diff --git a/Analysis/Tasks/PWGCF/GenericFramework/src/GFWWeights.cxx b/Analysis/Tasks/PWGCF/GenericFramework/src/GFWWeights.cxx new file mode 100644 index 0000000000000..14997ce739e62 --- /dev/null +++ b/Analysis/Tasks/PWGCF/GenericFramework/src/GFWWeights.cxx @@ -0,0 +1,458 @@ +/* +Author: Vytautas Vislavicius +Extention of Generic Flow (https://arxiv.org/abs/1312.3572) +*/ +#include "GenericFramework/GFWWeights.h" +#include "TMath.h" +GFWWeights::GFWWeights() : fDataFilled(kFALSE), + fMCFilled(kFALSE), + fW_data(0), + fW_mcrec(0), + fW_mcgen(0), + fEffInt(0), + fIntEff(0), + fAccInt(0), + fNbinsPt(0), + fbinsPt(0){}; +GFWWeights::~GFWWeights() +{ + delete fW_data; + delete fW_mcrec; + delete fW_mcgen; + delete fEffInt; + delete fIntEff; + delete fAccInt; + if (fbinsPt) + delete[] fbinsPt; +}; +void GFWWeights::SetPtBins(Int_t Nbins, Double_t* bins) +{ + if (fbinsPt) + delete[] fbinsPt; + fNbinsPt = Nbins; + fbinsPt = new Double_t[fNbinsPt + 1]; + for (Int_t i = 0; i <= fNbinsPt; ++i) + fbinsPt[i] = bins[i]; +}; +void GFWWeights::Init(Bool_t AddData, Bool_t AddMC) +{ + // fDataFilled = kFALSE; + // fMCFilled = kFALSE; + if (!fbinsPt) { //If pT bins not initialized, set to default (-1 to 1e6) to accept everything + fNbinsPt = 1; + fbinsPt = new Double_t[2]; + fbinsPt[0] = -1; + fbinsPt[1] = 1e6; + }; + if (AddData) { + fW_data = new TObjArray(); + fW_data->SetName("GFWWeights_Data"); + fW_data->SetOwner(kTRUE); + const char* tnd = GetBinName(0, 0, Form("data_%s", this->GetName())); + fW_data->Add(new TH3D(tnd, ";#varphi;#eta;v_{z}", 60, 0, TMath::TwoPi(), 64, -1.6, 1.6, 40, -10, 10)); + fDataFilled = kTRUE; + }; + if (AddMC) { + fW_mcrec = new TObjArray(); + fW_mcrec->SetName("GFWWeights_MCRec"); + fW_mcgen = new TObjArray(); + fW_mcgen->SetName("GFWWeights_MCGen"); + fW_mcrec->SetOwner(kTRUE); + fW_mcgen->SetOwner(kTRUE); + const char* tnr = GetBinName(0, 0, "mcrec"); //all integrated over cent. anyway + const char* tng = GetBinName(0, 0, "mcgen"); //all integrated over cent. anyway + fW_mcrec->Add(new TH3D(tnr, ";#it{p}_{T};#eta;v_{z}", fNbinsPt, 0, 20, 64, -1.6, 1.6, 40, -10, 10)); + fW_mcgen->Add(new TH3D(tng, ";#it{p}_{T};#eta;v_{z}", fNbinsPt, 0, 20, 64, -1.6, 1.6, 40, -10, 10)); + ((TH3D*)fW_mcrec->At(fW_mcrec->GetEntries() - 1))->GetXaxis()->Set(fNbinsPt, fbinsPt); + ((TH3D*)fW_mcgen->At(fW_mcgen->GetEntries() - 1))->GetXaxis()->Set(fNbinsPt, fbinsPt); + fMCFilled = kTRUE; + }; +}; + +void GFWWeights::Fill(Double_t phi, Double_t eta, Double_t vz, Double_t pt, Double_t cent, Int_t htype, Double_t weight) +{ + TObjArray* tar = 0; + const char* pf = ""; + if (htype == 0) { + tar = fW_data; + pf = Form("data_%s", this->GetName()); + }; + if (htype == 1) { + tar = fW_mcrec; + pf = "mcrec"; + }; + if (htype == 2) { + tar = fW_mcgen; + pf = "mcgen"; + }; + if (!tar) + return; + TH3D* th3 = (TH3D*)tar->FindObject(GetBinName(0, 0, pf)); //pT bin 0, V0M bin 0, since all integrated + if (!th3) { + if (!htype) + tar->Add(new TH3D(GetBinName(0, 0, pf), ";#varphi;#eta;v_{z}", 60, 0, TMath::TwoPi(), 64, -1.6, 1.6, 40, -10, 10)); //0,0 since all integrated + th3 = (TH3D*)tar->At(tar->GetEntries() - 1); + }; + th3->Fill(htype ? pt : phi, eta, vz, weight); +}; +Double_t GFWWeights::GetWeight(Double_t phi, Double_t eta, Double_t vz, Double_t pt, Double_t cent, Int_t htype) +{ + TObjArray* tar = 0; + const char* pf = ""; + if (htype == 0) { + tar = fW_data; + pf = "data"; + }; + if (htype == 1) { + tar = fW_mcrec; + pf = "mcrec"; + }; + if (htype == 2) { + tar = fW_mcgen; + pf = "mcgen"; + }; + if (!tar) + return 1; + TH3D* th3 = (TH3D*)tar->FindObject(GetBinName(0, 0, pf)); + if (!th3) + return 1; //-1; + Int_t xind = th3->GetXaxis()->FindBin(htype ? pt : phi); + Int_t etaind = th3->GetYaxis()->FindBin(eta); + Int_t vzind = th3->GetZaxis()->FindBin(vz); + Double_t weight = th3->GetBinContent(xind, etaind, vzind); + if (weight != 0) + return 1. / weight; + return 1; +}; +Double_t GFWWeights::GetNUA(Double_t phi, Double_t eta, Double_t vz) +{ + if (!fAccInt) + CreateNUA(); + Int_t xind = fAccInt->GetXaxis()->FindBin(phi); + Int_t etaind = fAccInt->GetYaxis()->FindBin(eta); + Int_t vzind = fAccInt->GetZaxis()->FindBin(vz); + Double_t weight = fAccInt->GetBinContent(xind, etaind, vzind); + if (weight != 0) + return 1. / weight; + return 1; +} +Double_t GFWWeights::GetNUE(Double_t pt, Double_t eta, Double_t vz) +{ + if (!fEffInt) + CreateNUE(); + Int_t xind = fEffInt->GetXaxis()->FindBin(pt); + Int_t etaind = fEffInt->GetYaxis()->FindBin(eta); + Int_t vzind = fEffInt->GetZaxis()->FindBin(vz); + Double_t weight = fEffInt->GetBinContent(xind, etaind, vzind); + if (weight != 0) + return 1. / weight; + return 1; +} +Double_t GFWWeights::FindMax(TH3D* inh, Int_t& ix, Int_t& iy, Int_t& iz) +{ + Double_t maxv = inh->GetBinContent(1, 1, 1); + for (Int_t i = 1; i <= inh->GetNbinsX(); i++) + for (Int_t j = 1; j <= inh->GetNbinsY(); j++) + for (Int_t k = 1; k <= inh->GetNbinsZ(); k++) + if (inh->GetBinContent(i, j, k) > maxv) { + ix = i; + iy = j; + iz = k; + maxv = inh->GetBinContent(i, j, k); + }; + return maxv; +}; +void GFWWeights::MCToEfficiency() +{ + if (fW_mcgen->GetEntries() < 1) { + printf("MC gen. array empty. This is probably because effs. have been calculated and the generated particle histograms have been cleared out!\n"); + return; + }; + for (Int_t i = 0; i < fW_mcrec->GetEntries(); i++) { + TH3D* hr = (TH3D*)fW_mcrec->At(i); + TH3D* hg = (TH3D*)fW_mcgen->At(i); + hr->Sumw2(); + hg->Sumw2(); + hr->Divide(hg); + }; + fW_mcgen->Clear(); +}; +void GFWWeights::RebinNUA(Int_t nX, Int_t nY, Int_t nZ) +{ + if (fW_data->GetEntries() < 1) + return; + for (Int_t i = 0; i < fW_data->GetEntries(); i++) { + ((TH3D*)fW_data->At(i))->RebinX(nX); + ((TH3D*)fW_data->At(i))->RebinY(nY); + ((TH3D*)fW_data->At(i))->RebinZ(nZ); + }; +}; +void GFWWeights::CreateNUA(Bool_t IntegrateOverCentAndPt) +{ + if (!IntegrateOverCentAndPt) { + printf("Method is outdated! NUA is integrated over centrality and pT. Quit now, or the behaviour will be bad\n"); + return; + }; + TH3D* h3; + TH1D* h1; + if (fW_data->GetEntries() < 1) + return; + if (IntegrateOverCentAndPt) { + if (fAccInt) + delete fAccInt; + fAccInt = (TH3D*)fW_data->At(0)->Clone("IntegratedAcceptance"); + //fAccInt->RebinY(2); this is rebinned already during the postprocessing + //fAccInt->RebinZ(5); + fAccInt->Sumw2(); + for (Int_t etai = 1; etai <= fAccInt->GetNbinsY(); etai++) { + fAccInt->GetYaxis()->SetRange(etai, etai); + if (fAccInt->Integral() < 1) + continue; + for (Int_t vzi = 1; vzi <= fAccInt->GetNbinsZ(); vzi++) { + fAccInt->GetZaxis()->SetRange(vzi, vzi); + if (fAccInt->Integral() < 1) + continue; + h1 = (TH1D*)fAccInt->Project3D("x"); + Double_t maxv = h1->GetMaximum(); + for (Int_t phii = 1; phii <= h1->GetNbinsX(); phii++) { + fAccInt->SetBinContent(phii, etai, vzi, fAccInt->GetBinContent(phii, etai, vzi) / maxv); + fAccInt->SetBinError(phii, etai, vzi, fAccInt->GetBinError(phii, etai, vzi) / maxv); + }; + delete h1; + }; + fAccInt->GetZaxis()->SetRange(1, fAccInt->GetNbinsZ()); + }; + fAccInt->GetYaxis()->SetRange(1, fAccInt->GetNbinsY()); + return; + }; +}; +TH1D* GFWWeights::GetdNdPhi() +{ + TH3D* temph = (TH3D*)fW_data->At(0)->Clone("tempH3"); + TH1D* reth = (TH1D*)temph->Project3D("x"); + reth->SetName("RetHist"); + delete temph; + Double_t max = reth->GetMaximum(); + if (max == 0) + return 0; + for (Int_t phi = 1; phi <= reth->GetNbinsX(); phi++) { + if (reth->GetBinContent(phi) == 0) + continue; + reth->SetBinContent(phi, reth->GetBinContent(phi) / max); + reth->SetBinError(phi, reth->GetBinError(phi) / max); + } + return reth; +} +void GFWWeights::CreateNUE(Bool_t IntegrateOverCentrality) +{ + if (!IntegrateOverCentrality) { + printf("Method is outdated! NUE is integrated over centrality. Quit now, or the behaviour will be bad\n"); + return; + }; + TH3D* num = 0; + TH3D* den = 0; + if (fW_mcrec->GetEntries() < 1 || fW_mcgen->GetEntries() < 1) + return; + if (IntegrateOverCentrality) { + num = (TH3D*)fW_mcrec->At(0); //->Clone(Form("temp_%s",fW_mcrec->At(0)->GetName())); + den = (TH3D*)fW_mcgen->At(0); //->Clone(Form("temp_%s",fW_mcgen->At(0)->GetName())); + num->Sumw2(); + den->Sumw2(); + num->RebinY(2); + den->RebinY(2); + num->RebinZ(5); + den->RebinZ(5); + fEffInt = (TH3D*)num->Clone("Efficiency_Integrated"); + fEffInt->Divide(den); + return; + }; +}; +void GFWWeights::ReadAndMerge(TString filelinks, TString listName, Bool_t addData, Bool_t addRec, Bool_t addGen) +{ + FILE* flist = fopen(filelinks.Data(), "r"); + char str[150]; + Int_t nFiles = 0; + while (fscanf(flist, "%s\n", str) == 1) + nFiles++; + rewind(flist); + if (nFiles == 0) { + printf("No files to read!\n"); + return; + }; + if (!fW_data && addData) { + fW_data = new TObjArray(); + fW_data->SetName("Weights_Data"); + fW_data->SetOwner(kTRUE); + }; + if (!fW_mcrec && addRec) { + fW_mcrec = new TObjArray(); + fW_mcrec->SetName("Weights_MCRec"); + fW_mcrec->SetOwner(kTRUE); + }; + if (!fW_mcgen && addGen) { + fW_mcgen = new TObjArray(); + fW_mcgen->SetName("Weights_MCGen"); + fW_mcgen->SetOwner(kTRUE); + }; + // fDataFilled = kFALSE; + // fMCFilled = kFALSE; + TFile* tf = 0; + for (Int_t i = 0; i < nFiles; i++) { + Int_t trash = fscanf(flist, "%s\n", str); + tf = new TFile(str, "READ"); + if (tf->IsZombie()) { + printf("Could not open file %s!\n", str); + tf->Close(); + continue; + }; + TList* tl = (TList*)tf->Get(listName.Data()); + GFWWeights* tw = (GFWWeights*)tl->FindObject(this->GetName()); + if (!tw) { + printf("Could not fetch weights object from %s\n", str); + tf->Close(); + continue; + }; + if (addData) + AddArray(fW_data, tw->GetDataArray()); + if (addRec) + AddArray(fW_mcrec, tw->GetRecArray()); + if (addGen) + AddArray(fW_mcgen, tw->GetGenArray()); + tf->Close(); + delete tw; + }; +}; +void GFWWeights::AddArray(TObjArray* targ, TObjArray* sour) +{ + if (!sour) { + printf("Source array does not exist!\n"); + return; + }; + for (Int_t i = 0; i < sour->GetEntries(); i++) { + TH3D* sourh = (TH3D*)sour->At(i); + TH3D* targh = (TH3D*)targ->FindObject(sourh->GetName()); + if (!targh) { + targh = (TH3D*)sourh->Clone(sourh->GetName()); + targh->SetDirectory(0); + targ->Add(targh); + } else + targh->Add(sourh); + }; +}; +void GFWWeights::OverwriteNUA() +{ + if (!fAccInt) + CreateNUA(); + TString ts(fW_data->At(0)->GetName()); + TH3D* trash = (TH3D*)fW_data->RemoveAt(0); + delete trash; + fW_data->Add((TH3D*)fAccInt->Clone(ts.Data())); + delete fAccInt; +} +Long64_t GFWWeights::Merge(TCollection* collist) +{ + Long64_t nmerged = 0; + if (!fW_data) { + fW_data = new TObjArray(); + fW_data->SetName("Weights_Data"); + fW_data->SetOwner(kTRUE); + }; + if (!fW_mcrec) { + fW_mcrec = new TObjArray(); + fW_mcrec->SetName("Weights_MCRec"); + fW_mcrec->SetOwner(kTRUE); + }; + if (!fW_mcgen) { + fW_mcgen = new TObjArray(); + fW_mcgen->SetName("Weights_MCGen"); + fW_mcgen->SetOwner(kTRUE); + }; + GFWWeights* l_w = 0; + TIter all_w(collist); + while (l_w = ((GFWWeights*)all_w())) { + AddArray(fW_data, l_w->GetDataArray()); + AddArray(fW_mcrec, l_w->GetRecArray()); + AddArray(fW_mcgen, l_w->GetGenArray()); + nmerged++; + }; + return nmerged; +}; +TH1D* GFWWeights::GetIntegratedEfficiencyHist() +{ + if (!fW_mcgen) { + printf("MCGen array does not exist!\n"); + return 0; + }; + if (!fW_mcrec) { + printf("MCRec array does not exist!\n"); + return 0; + }; + if (!fW_mcgen->GetEntries()) { + printf("MCGen array is empty!\n"); + return 0; + }; + if (!fW_mcrec->GetEntries()) { + printf("MCRec array is empty!\n"); + return 0; + }; + TH3D* num = (TH3D*)fW_mcrec->At(0)->Clone("Numerator"); + for (Int_t i = 1; i < fW_mcrec->GetEntries(); i++) + num->Add((TH3D*)fW_mcrec->At(i)); + TH3D* den = (TH3D*)fW_mcgen->At(0)->Clone("Denominator"); + for (Int_t i = 1; i < fW_mcgen->GetEntries(); i++) + den->Add((TH3D*)fW_mcgen->At(i)); + TH1D* num1d = (TH1D*)num->Project3D("x"); + num1d->SetName("retHist"); + num1d->Sumw2(); + TH1D* den1d = (TH1D*)den->Project3D("x"); + den1d->Sumw2(); + num1d->Divide(den1d); + delete num; + delete den; + delete den1d; + return num1d; +} +Bool_t GFWWeights::CalculateIntegratedEff() +{ + if (fIntEff) + delete fIntEff; + fIntEff = GetIntegratedEfficiencyHist(); + if (!fIntEff) { + return kFALSE; + }; + fIntEff->SetName("IntegratedEfficiency"); + return kTRUE; +} +Double_t GFWWeights::GetIntegratedEfficiency(Double_t pt) +{ + if (!fIntEff) + if (!CalculateIntegratedEff()) + return 0; + return fIntEff->GetBinContent(fIntEff->FindBin(pt)); +} +TH1D* GFWWeights::GetEfficiency(Double_t etamin, Double_t etamax, Double_t vzmin, Double_t vzmax) +{ + TH3D* num = (TH3D*)fW_mcrec->At(0)->Clone("Numerator"); + for (Int_t i = 1; i < fW_mcrec->GetEntries(); i++) + num->Add((TH3D*)fW_mcrec->At(i)); + TH3D* den = (TH3D*)fW_mcgen->At(0)->Clone("Denominator"); + for (Int_t i = 1; i < fW_mcgen->GetEntries(); i++) + den->Add((TH3D*)fW_mcgen->At(i)); + Int_t eb1 = num->GetYaxis()->FindBin(etamin + 1e-6); + Int_t eb2 = num->GetYaxis()->FindBin(etamax - 1e-6); + Int_t vz1 = num->GetZaxis()->FindBin(vzmin + 1e-6); + Int_t vz2 = num->GetZaxis()->FindBin(vzmax - 1e-6); + num->GetYaxis()->SetRange(eb1, eb2); + num->GetZaxis()->SetRange(vz1, vz2); + den->GetYaxis()->SetRange(eb1, eb2); + den->GetZaxis()->SetRange(vz1, vz2); + TH1D* num1d = (TH1D*)num->Project3D("x"); + TH1D* den1d = (TH1D*)den->Project3D("x"); + delete num; + delete den; + num1d->Sumw2(); + den1d->Sumw2(); + num1d->Divide(den1d); + delete den1d; + return num1d; +} \ No newline at end of file diff --git a/Analysis/Tasks/PWGCF/GenericFramework/src/GenericFrameworkLinkDef.h b/Analysis/Tasks/PWGCF/GenericFramework/src/GenericFrameworkLinkDef.h new file mode 100644 index 0000000000000..866cb5d993eed --- /dev/null +++ b/Analysis/Tasks/PWGCF/GenericFramework/src/GenericFrameworkLinkDef.h @@ -0,0 +1,20 @@ +// 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. + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class GFW + ; +#pragma link C++ class GFWCumulant + ; +#pragma link C++ class ProfileSubset + ; +#pragma link C++ class FlowContainer + ; +#pragma link C++ class GFWWeights + ; \ No newline at end of file diff --git a/Analysis/Tasks/PWGCF/GenericFramework/src/ProfileSubset.cxx b/Analysis/Tasks/PWGCF/GenericFramework/src/ProfileSubset.cxx new file mode 100644 index 0000000000000..e37de22c92d22 --- /dev/null +++ b/Analysis/Tasks/PWGCF/GenericFramework/src/ProfileSubset.cxx @@ -0,0 +1,114 @@ +/* +Author: Vytautas Vislavicius +Extention of Generic Flow (https://arxiv.org/abs/1312.3572) +*/ +#include "GenericFramework/ProfileSubset.h" +#include "TProfile2D.h" + +TProfile* ProfileSubset::GetSubset(Bool_t onX, const char* name, Int_t firstbin, Int_t lastbin, Int_t l_nbins, Double_t* l_binarray) +{ + TString expectedName = (onX ? "_pfx" : "_pfy"); + TString pname(name); + if (pname.IsNull() || name == expectedName) + pname = TString(GetName()) + expectedName; + const TAxis& outAxis = (onX ? fXaxis : fYaxis); + const TArrayD* bins = outAxis.GetXbins(); + Int_t firstOutBin = outAxis.GetFirst(); + Int_t lastOutBin = outAxis.GetLast(); + //printf("firstOutBin = %i, lastOutBin = %i\n",firstOutBin,lastOutBin); + TProfile* p1 = 0; + if (l_nbins) + p1 = new TProfile(pname, GetTitle(), l_nbins, l_binarray); + else + p1 = new TProfile(pname, GetTitle(), outAxis.GetNbins(), bins->fArray); + //printf("p1 has %i bins (l_nbins = %i)\n",p1->GetNbinsX(),l_nbins); + if (fBinSumw2.fN) + p1->Sumw2(); + TH2D* h2dW = ProjectionXY("h2temp-W", "W"); + TH2D* h2dN = ProjectionXY("h2temp-N", "B"); + h2dW->SetDirectory(0); + h2dN->SetDirectory(0); + if (onX) { + h2dW->GetXaxis()->SetRange(firstOutBin, lastOutBin); + h2dN->GetXaxis()->SetRange(firstOutBin, lastOutBin); + } else { + h2dW->GetYaxis()->SetRange(firstOutBin, lastOutBin); + h2dN->GetYaxis()->SetRange(firstOutBin, lastOutBin); + } + TH1D* h1W = (onX) ? h2dW->ProjectionX("h1temp-W", firstbin, lastbin) : h2dW->ProjectionY("h1temp-W", firstbin, lastbin); + TH1D* h1N = (onX) ? h2dN->ProjectionX("h1temp-N", firstbin, lastbin) : h2dN->ProjectionY("h1temp-N", firstbin, lastbin); + h1W->SetDirectory(0); + h1N->SetDirectory(0); + //printf("Asserting, %i vs. %i\n",h1W->fN, p1->fN); + R__ASSERT(h1W->fN == p1->fN); + R__ASSERT(h1N->fN == p1->fN); + R__ASSERT(h1W->GetSumw2()->fN != 0); // h1W should always be a weighted histogram since h2dW is + for (int i = 0; i < p1->fN; ++i) { + p1->fArray[i] = h1W->GetBinContent(i); // array of profile is sum of all values + p1->GetSumw2()->fArray[i] = h1W->GetSumw2()->fArray[i]; // array of content square of profile is weight square of the W projected histogram + p1->SetBinEntries(i, h1N->GetBinContent(i)); + if (fBinSumw2.fN) + p1->GetBinSumw2()->fArray[i] = h1N->GetSumw2()->fArray[i]; // sum of weight squares are stored to compute errors in h1N histogram + } + delete h2dW; + delete h2dN; + delete h1W; + delete h1N; + p1->SetEntries(p1->GetEffectiveEntries()); + return p1; +}; +void ProfileSubset::OverrideBinContent(Double_t x, Double_t y, Double_t x2, Double_t y2, Double_t val) +{ + if (!fBinSumw2.fN) + Sumw2(); + TH2D* h2dW = ProjectionXY("h2temp-W", "W"); + TH2D* h2dN = ProjectionXY("h2temp-N", "B"); + Int_t binIndex = FindBin(x, y); + Int_t binIndex2 = FindBin(x2, y2); + fArray[binIndex] = h2dW->GetBinContent(binIndex2); + GetSumw2()->fArray[binIndex] = h2dW->GetSumw2()->fArray[binIndex2]; + SetBinEntries(binIndex, h2dN->GetBinContent(binIndex2)); + if (fBinSumw2.fN) + GetBinSumw2()->fArray[binIndex] = h2dN->GetSumw2()->fArray[binIndex2]; +} +void ProfileSubset::OverrideBinContent(Double_t x, Double_t y, Double_t x2, Double_t y2, TProfile2D* sourceProf) +{ + if (!fBinSumw2.fN) + Sumw2(); + if (!sourceProf->fN) + sourceProf->Sumw2(); + TH2D* h2dW = sourceProf->ProjectionXY("h2temp-W", "W"); + TH2D* h2dN = sourceProf->ProjectionXY("h2temp-N", "B"); + Int_t binIndex = FindBin(x, y); + Int_t binIndex2 = sourceProf->FindBin(x2, y2); + fArray[binIndex] = h2dW->GetBinContent(binIndex2); + GetSumw2()->fArray[binIndex] = h2dW->GetSumw2()->fArray[binIndex2]; + SetBinEntries(binIndex, h2dN->GetBinContent(binIndex2)); + if (fBinSumw2.fN) + GetBinSumw2()->fArray[binIndex] = h2dN->GetSumw2()->fArray[binIndex2]; +} +Bool_t ProfileSubset::OverrideBinsWithZero(Int_t xb1, Int_t yb1, Int_t xb2, Int_t yb2) +{ + Bool_t lHaveToQuit = kFALSE; + if (GetNbinsX() < xb1 || GetNbinsX() < xb2) { + lHaveToQuit = kTRUE; + printf("xBins out of range! (%i-%i vs %i)\n", xb1, xb2, GetNbinsX()); + }; + if (GetNbinsY() < yb1 || GetNbinsY() < yb2) { + lHaveToQuit = kTRUE; + printf("yBins out of range! (%i-%i vs %i)\n", yb1, yb2, GetNbinsY()); + }; + if (lHaveToQuit) + return kFALSE; + for (Int_t ix = xb1; ix <= xb2; ix++) { + for (Int_t iy = yb1; iy <= yb2; iy++) { + Int_t bind = FindBin(GetXaxis()->GetBinCenter(ix), GetYaxis()->GetBinCenter(iy)); + fArray[bind] = 0; + GetSumw2()->fArray[bind] = 0; + SetBinEntries(bind, 0); + if (fBinSumw2.fN) + GetBinSumw2()->fArray[bind] = 0; + } + } + return kTRUE; +} \ No newline at end of file