diff --git a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx index 62974a0c885..aa837b02233 100644 --- a/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx +++ b/PWGEM/PhotonMeson/Tasks/taskPi0FlowEMC.cxx @@ -50,12 +50,14 @@ #include #include #include // IWYU pragma: keep +#include #include #include #include #include #include +#include #include #include #include @@ -100,6 +102,8 @@ enum Harmonics { }; struct TaskPi0FlowEMC { + static constexpr float MinEnergy = 0.7f; + // configurable for flow Configurable harmonic{"harmonic", 2, "harmonic number"}; Configurable qvecDetector{"qvecDetector", 0, "Detector for Q vector estimation (FT0M: 0, FT0A: 1, FT0C: 2, TPC Pos: 3, TPC Neg: 4, TPC Tot: 5)"}; @@ -129,6 +133,7 @@ struct TaskPi0FlowEMC { ConfigurableAxis thnConfigAxisCosDeltaPhi{"thnConfigAxisCosDeltaPhi", {8, -1., 1.}, ""}; ConfigurableAxis thnConfigAxisScalarProd{"thnConfigAxisScalarProd", {100, -5., 5.}, ""}; ConfigurableAxis thnConfigAxisM02{"thnConfigAxisM02", {200, 0., 5.}, ""}; + ConfigurableAxis thnConfigAxisEnergyCalib{"thnConfigAxisEnergyCalib", {200, 0., 20.}, ""}; EMPhotonEventCut fEMEventCut; struct : ConfigurableGroup { @@ -195,6 +200,7 @@ struct TaskPi0FlowEMC { Configurable cfgSpresoPath{"cfgSpresoPath", "Users/m/mhemmer/EM/Flow/Resolution", "Path to SP resolution file"}; Configurable cfgApplySPresolution{"cfgApplySPresolution", 0, "Apply resolution correction"}; Configurable doEMCalCalib{"doEMCalCalib", 0, "Produce output for EMCal calibration"}; + Configurable cfgEnableNonLin{"cfgEnableNonLin", false, "flag to turn extra non linear energy calibration on/off"}; } correctionConfig; SliceCache cache; @@ -209,6 +215,7 @@ struct TaskPi0FlowEMC { using EMCalPhotons = soa::Join; using FilteredCollsWithQvecs = soa::Filtered>; using CollsWithQvecs = soa::Join; + using Colls = soa::Join; Preslice perCollisionEMC = aod::emccluster::emeventId; @@ -230,6 +237,9 @@ struct TaskPi0FlowEMC { // static constexpr static constexpr int64_t NMinPhotonRotBkg = 3; + // Usage when cfgEnableNonLin is enabled + std::unique_ptr fEMCalCorrectionFactor; // ("fEMCalCorrectionFactor","(1 + [0]/x + [1]/x^2) / (1 + [2]/x)", 0.3, 100.); + // To access the 1D array inline int getIndex(int iEta, int iPhi) { @@ -308,10 +318,10 @@ struct TaskPi0FlowEMC { const AxisSpec thnAxisM02{thnConfigAxisM02, "M_{02}"}; const AxisSpec thAxisTanThetaPhi{mesonConfig.thConfigAxisTanThetaPhi, "atan(#Delta#theta/#Delta#varphi)"}; const AxisSpec thAxisClusterEnergy{thnConfigAxisPt, "#it{E} (GeV)"}; + const AxisSpec thAxisEnergyCalib{thnConfigAxisEnergyCalib, "#it{E}_{clus} (GeV)"}; const AxisSpec thAxisAlpha{100, -1., +1, "#alpha"}; const AxisSpec thAxisMult{1000, 0., +1000, "#it{N}_{ch}"}; const AxisSpec thAxisEnergy{1000, 0., 100., "#it{E}_{clus} (GeV)"}; - const AxisSpec thAxisEnergyCalib{400, 0., 20., "#it{E}_{clus} (GeV)"}; const AxisSpec thAxisTime{1500, -600, 900, "#it{t}_{cl} (ns)"}; const AxisSpec thAxisEta{320, -0.8, 0.8, "#eta"}; const AxisSpec thAxisPhi{500, 0, 2 * 3.14159, "phi"}; @@ -439,6 +449,9 @@ struct TaskPi0FlowEMC { LOG(info) << "thnConfigAxisInvMass.value[1] = " << thnConfigAxisInvMass.value[1] << " thnConfigAxisInvMass.value.back() = " << thnConfigAxisInvMass.value.back(); LOG(info) << "thnConfigAxisPt.value[1] = " << thnConfigAxisPt.value[1] << " thnConfigAxisPt.value.back() = " << thnConfigAxisPt.value.back(); + + fEMCalCorrectionFactor = std::make_unique("fEMCalCorrectionFactor", "(1 + [0]/x + [1]/x^2) / (1 + [2]/x)", 0.3, 100.); + fEMCalCorrectionFactor->SetParameters(-5.33426e-01, 1.40144e-02, -5.24434e-01); }; // end init /// Change radians to degree @@ -475,7 +488,8 @@ struct TaskPi0FlowEMC { /// Get the centrality /// \param collision is the collision with the centrality information - float getCentrality(CollsWithQvecs::iterator const& collision) + template + float getCentrality(TCollision const& collision) { float cent = -999.; switch (centEstimator) { @@ -728,7 +742,11 @@ struct TaskPi0FlowEMC { if (checkEtaPhi1D(photon.eta(), RecoDecay::constrainAngle(photon.phi())) >= cfgEMCalMapLevelBackground.value) { continue; } - ROOT::Math::PtEtaPhiMVector photon3(photon.pt(), photon.eta(), photon.phi(), 0.); + float energyCorrectionFactor = 1.f; + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(photon.e() > MinEnergy ? photon.e() : MinEnergy); + } + ROOT::Math::PtEtaPhiMVector photon3(energyCorrectionFactor * photon.pt(), photon.eta(), photon.phi(), 0.); if (iCellIDPhoton1 >= 0) { ROOT::Math::PtEtaPhiMVector mother1 = photon1 + photon3; float openingAngle1 = std::acos(photon1.Vect().Dot(photon3.Vect()) / (photon1.P() * photon3.P())); @@ -780,8 +798,8 @@ struct TaskPi0FlowEMC { } /// \brief Calculate background using rotation background method for calib - template - void rotationBackgroundCalib(const ROOT::Math::PtEtaPhiMVector& meson, ROOT::Math::PtEtaPhiMVector photon1, ROOT::Math::PtEtaPhiMVector photon2, TPhotons const& photons_coll, unsigned int ig1, unsigned int ig2, CollsWithQvecs::iterator const& collision) + template + void rotationBackgroundCalib(const ROOT::Math::PtEtaPhiMVector& meson, ROOT::Math::PtEtaPhiMVector photon1, ROOT::Math::PtEtaPhiMVector photon2, TPhotons const& photons_coll, unsigned int ig1, unsigned int ig2, TCollision const& collision) { // if less than 3 clusters are present skip event since we need at least 3 clusters if (photons_coll.size() < NMinPhotonRotBkg) { @@ -817,7 +835,11 @@ struct TaskPi0FlowEMC { if (checkEtaPhi1D(photon.eta(), RecoDecay::constrainAngle(photon.phi())) >= cfgEMCalMapLevelBackground.value) { continue; } - ROOT::Math::PtEtaPhiMVector photon3(photon.pt(), photon.eta(), photon.phi(), 0.); + float energyCorrectionFactor = 1.f; + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(photon.e() > MinEnergy ? photon.e() : MinEnergy); + } + ROOT::Math::PtEtaPhiMVector photon3(energyCorrectionFactor * photon.pt(), photon.eta(), photon.phi(), 0.); if (iCellIDPhoton1 >= 0) { if (std::fabs((photon1.E() - photon3.E()) / (photon1.E() + photon3.E()) < cfgMaxAsymmetry)) { // only use symmetric decays ROOT::Math::PtEtaPhiMVector mother1 = photon1 + photon3; @@ -893,6 +915,10 @@ struct TaskPi0FlowEMC { void processEMCal(CollsWithQvecs const& collisions, EMCalPhotons const& clusters) { int nColl = 1; + float energyCorrectionFactor = 1.f; + if (cfgDoReverseScaling.value) { + energyCorrectionFactor = 1.0505f; + } for (const auto& collision : collisions) { auto photonsPerCollision = clusters.sliceBy(perCollisionEMC, collision.globalIndex()); @@ -971,18 +997,14 @@ struct TaskPi0FlowEMC { continue; } } - - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - if (cfgDoReverseScaling.value) { - // Convert to PxPyPzEVector to modify energy - ROOT::Math::PxPyPzEVector v1Mod(v1); - v1Mod.SetE(v1Mod.E() * 1.0505); - v1 = ROOT::Math::PtEtaPhiMVector(v1Mod.Pt(), v1Mod.Eta(), v1Mod.Phi(), 0.); - ROOT::Math::PxPyPzEVector v2Mod(v2); - v2Mod.SetE(v2Mod.E() * 1.0505); - v2 = ROOT::Math::PtEtaPhiMVector(v2Mod.Pt(), v2Mod.Eta(), v2Mod.Phi(), 0.); + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g1.e() > MinEnergy ? g1.e() : MinEnergy); } + ROOT::Math::PtEtaPhiMVector v1(energyCorrectionFactor * g1.pt(), g1.eta(), g1.phi(), 0.); + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g2.e() > MinEnergy ? g2.e() : MinEnergy); + } + ROOT::Math::PtEtaPhiMVector v2(energyCorrectionFactor * g2.pt(), g2.eta(), g2.phi(), 0.); ROOT::Math::PtEtaPhiMVector vMeson = v1 + v2; float dTheta = v1.Theta() - v2.Theta(); float dPhi = v1.Phi() - v2.Phi(); @@ -1031,6 +1053,10 @@ struct TaskPi0FlowEMC { // Pi0 from EMCal void processEMCalMixed(FilteredCollsWithQvecs const& collisions, FilteredEMCalPhotons const& clusters) { + float energyCorrectionFactor = 1.f; + if (cfgDoReverseScaling.value) { + energyCorrectionFactor = 1.0505f; + } auto getClustersSize = [&clusters, this](FilteredCollsWithQvecs::iterator const& col) { auto associatedClusters = clusters.sliceByCached(emccluster::emeventId, col.globalIndex(), this->cache); // it's cached, so slicing/grouping happens only once @@ -1079,18 +1105,14 @@ struct TaskPi0FlowEMC { continue; } } - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - - if (cfgDoReverseScaling.value) { - // Convert to PxPyPzEVector to modify energy - ROOT::Math::PxPyPzEVector v1Mod(v1); - v1Mod.SetE(v1Mod.E() * 1.0505); - v1 = ROOT::Math::PtEtaPhiMVector(v1Mod.Pt(), v1Mod.Eta(), v1Mod.Phi(), 0.); - ROOT::Math::PxPyPzEVector v2Mod(v2); - v2Mod.SetE(v2Mod.E() * 1.0505); - v2 = ROOT::Math::PtEtaPhiMVector(v2Mod.Pt(), v2Mod.Eta(), v2Mod.Phi(), 0.); + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g1.e() > MinEnergy ? g1.e() : MinEnergy); + } + ROOT::Math::PtEtaPhiMVector v1(energyCorrectionFactor * g1.pt(), g1.eta(), g1.phi(), 0.); + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g2.e() > MinEnergy ? g2.e() : MinEnergy); } + ROOT::Math::PtEtaPhiMVector v2(energyCorrectionFactor * g2.pt(), g2.eta(), g2.phi(), 0.); ROOT::Math::PtEtaPhiMVector vMeson = v1 + v2; float dTheta = v1.Theta() - v2.Theta(); @@ -1247,8 +1269,9 @@ struct TaskPi0FlowEMC { PROCESS_SWITCH(TaskPi0FlowEMC, processResolution, "Process resolution", false); // EMCal calibration - void processEMCalCalib(CollsWithQvecs const& collisions, EMCalPhotons const& clusters) + void processEMCalCalib(Colls const& collisions, EMCalPhotons const& clusters) { + float energyCorrectionFactor = 1.f; if (!correctionConfig.doEMCalCalib) { return; } @@ -1269,10 +1292,6 @@ struct TaskPi0FlowEMC { // event selection continue; } - if (!isQvecGood(getAllQvec(collision))) { - // selection based on QVector - continue; - } runNow = collision.runNumber(); if (runNow != runBefore) { initCCDB(collision); @@ -1306,18 +1325,16 @@ struct TaskPi0FlowEMC { } } - ROOT::Math::PtEtaPhiMVector v1(g1.pt(), g1.eta(), g1.phi(), 0.); - ROOT::Math::PtEtaPhiMVector v2(g2.pt(), g2.eta(), g2.phi(), 0.); - if (cfgDoReverseScaling.value) { - // Convert to PxPyPzEVector to modify energy - ROOT::Math::PxPyPzEVector v1Mod(v1); - v1Mod.SetE(v1Mod.E() * 1.0505); - v1 = ROOT::Math::PtEtaPhiMVector(v1Mod.Pt(), v1Mod.Eta(), v1Mod.Phi(), 0.); - ROOT::Math::PxPyPzEVector v2Mod(v2); - v2Mod.SetE(v2Mod.E() * 1.0505); - v2 = ROOT::Math::PtEtaPhiMVector(v2Mod.Pt(), v2Mod.Eta(), v2Mod.Phi(), 0.); + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g1.e() > MinEnergy ? g1.e() : MinEnergy); } + ROOT::Math::PtEtaPhiMVector v1(energyCorrectionFactor * g1.pt(), g1.eta(), g1.phi(), 0.); + if (correctionConfig.cfgEnableNonLin.value) { + energyCorrectionFactor = fEMCalCorrectionFactor->Eval(g2.e() > MinEnergy ? g2.e() : MinEnergy); + } + ROOT::Math::PtEtaPhiMVector v2(energyCorrectionFactor * g2.pt(), g2.eta(), g2.phi(), 0.); ROOT::Math::PtEtaPhiMVector vMeson = v1 + v2; + float dTheta = v1.Theta() - v2.Theta(); float dPhi = v1.Phi() - v2.Phi(); float openingAngle = std::acos(v1.Vect().Dot(v2.Vect()) / (v1.P() * v2.P()));